當 Goodies 在 Ethereum Classic 鏈上提供 ETC 退款時,我如何驗證我的 The DAO 代幣餘額是否正確?
從部落格文章The White Hats and DAO Wars: 幕後,Goodies 打算:
開發智能合約,用於將 ETC 分配到區塊 1,919,999 持有 DAO 代幣的地址。
更新時間 2016 年 8 月 20 日 00:57 UTC
從待審核的 ETC 撤回合約中,位於 0x180826b05452ce96e157f0708c43381fee64a6b8 的DAOBalanceSnapShot合約將用於確定 DAO 代幣持有者(DTH)在硬分叉前區塊 1,919,999 的餘額。
- Daobalance 目錄,包含 dao_balance_snapshot.sol 合約和生成數據的腳本。這是從 ETH 鏈填充的,但部署在 ETC 鏈中,並包含硬分叉時的 DAO 代幣持有者余額。該合約已經部署並填充了 ETC 鏈中 0x180826b05452ce96e157f0708c43381fee64a6b8 的數據。您可以使用 geth 中的以下介面對其進行實時測試:
var daobalancesnapshot_abi =
$$ {“constant”:true,“inputs”:[],“name”:“totalSupply”,“outputs”:[{“name”:"",“type”:“uint256”}],“type”:“function”},{“constant”:false,“inputs”:[],“name”:“seal”,“outputs”:[],“type”:“function”},{“constant”:true,“inputs”:[],“name”:“totalAccounts”,“outputs”:[{“name”:"",“type”:“uint256”}],“type”:“function”},{“constant”:true,“inputs”:[{“name”:"",“type”:“address”}],“name”:“balanceOf”,“outputs”:[{“name”:"",“type”:“uint256”}],“type”:“function”},{“constant”:false,“inputs”:[{“name”:“data”,“type”:“uint256[]”}],“name”:“fill”,“outputs”:[],“type”:“function”},{“constant”:true,“inputs”:[],“name”:“owner”,“outputs”:[{“name”:"",“type”:“address”}],“type”:“function”},{“constant”:true,“inputs”:[],“name”:“sealed”,“outputs”:[{“name”:"",“type”:“bool”}],“type”:“function”},{“inputs”:[],“type”:“constructor”} $$; var daobalancesnapshot = web3.eth.contract(daobalancesnapshot_abi).at(“0x180826b05452ce96e157f0708c43381fee64a6b8”);
daobalancesnapshot.balanceOf(YOURACCOUNTHERE);
當 Goodies 在 Ethereum Classic 鏈上提供 ETC 退款時,我如何驗證我的 The DAO 代幣餘額是否正確?
更新時間 2016 年 8 月 20 日 00:57 UTC -
BigNumber
用於準確計算totalSupply
數字。檢查你的 DAO 代幣餘額
從要審查的 ETC 撤回契約中,
geth
您可以使用以下命令同步到乙太坊經典鏈,檢查硬分叉前區塊 1,919,999 處的 DAO 代幣餘額:geth --fast --oppose-dao-fork console // Allow the chain to sync > var daobalancesnapshot_abi = [{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[],"name":"seal","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"totalAccounts","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"data","type":"uint256[]"}],"name":"fill","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[],"name":"sealed","outputs":[{"name":"","type":"bool"}],"type":"function"},{"inputs":[],"type":"constructor"}]; undefined > var daobalancesnapshot = web3.eth.contract(daobalancesnapshot_abi).at("0x180826b05452ce96e157f0708c43381fee64a6b8"); undefined > daobalancesnapshot.balanceOf(YOURACCOUNTHERE); 123456
或者,您可以在 theDAOTokenBalance_20160819_155742UTC_balance.xlsx 中驗證區塊 1,919,999 處的 DAO 代幣餘額。您可能必須點擊滑鼠右鍵 -> 將連結另存為才能將電子表格下載到您的電腦。
檢查所有 DAO 代幣餘額
腳本getTheDAOTokenBalance查找
CreatedToken
與The DAO 事件相關的所有地址,並根據 The DAO 的函式 AT 塊 1,919,999Transfer
查詢每個地址。balanceOf(...)
該腳本還將此結果與位於0x180826b05452ce96e157f0708c43381fee64a6b8 (此處帶有 ABI )處的
DAOBalanceSnapShot
合約進行核對,Goodies 打算使用該合約來確定每個地址在第 1,919,999 塊處擁有的 DAO 代幣的數量。結果是,與 Goodies 的合約相比,我的腳本為每個地址計算了相同數量的 The DAO 代幣,
DAOBalanceSnapShot
並且總數相同。在github.com/bokkypoobah/TheDAOETCTokenBalance上有一個總結。您可以在 DAOTokenBalance_20160819_155742UTC_creation.txt 中找到所有
CreatedToken
事件,在DAOTokenBalance_20160819_155742UTC_transfer.txt中找到所有事件,以及Transfer
在DAOTokenBalance_20160819_155742UTC_balance.txt和 DAO_ls915742UTC_balance.txt中找到第 1,919,999塊的所有餘額。我的腳本總共找到 22,092 個非零賬戶,總共 1,153,816,598.7024671407837618 個 DAO。我的腳本查詢 Goodies 的
DAOBalanceSnapShot
合約並找到相同的 DAO 總數。該DAOBalanceSnapShot
合約有一個totalSupply
屬性,返回值 11538165987024671407837618 或 1,153,816,598.7024671407837618 DAO。Goodies 的DAOBalanceSnapShot
合約準確地表示了 DTH 在硬分叉前區塊 1,919,999 的賬戶餘額。並
totalSupply()
在硬分叉前的區塊 1,919,999 處檢查 DAO,geth
確認總供應量。> var theDAOABIFragment = [{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"type":"function"}]; undefined > var theDAOAddress = "0xbb9bc244d798123fde783fcc1c72d3bb8c189413" undefined > var theDAO = web3.eth.contract(theDAOABIFragment).at(theDAOAddress); undefined > theDAO.totalSupply(1919999).toString(10); "11538165987024671407837618"
劇本
要使用以下腳本,您必須使用
geth --oppose-dao-fork console
. 請注意,您不能使用該--fast
參數,因為這將排除debug.traceTransaction(...)
API 查詢所需的中間結果,以確定令牌創建所涉及的正確地址。該腳本將需要半天以上的時間來執行,具體取決於您的處理器和磁碟的速度。#!/bin/sh # ------------------------------------------------------------------------------ # Retrieve The DAO Creation and Transfer events, collecting addresses. Then # retrieve the pre-hard-fork balances and the current balances for these # addresses. # # v2 improvements # * Summing totals as BigNumbers instead of floats # * Only including non-zero balances at block 1919999 in counter # # Usage: # 1. Download this script to getTheDAOTokenBalance . # 2. `chmod 700 getTheDAOTokenBalance` # 3. Run `geth console` in a window. # 4. Then run this script `./getTheDAOTokenBalance` in a separate window. # # Enjoy. (c) BokkyPooBah 2016. The MIT licence. # ------------------------------------------------------------------------------ DATE=`date -u +%Y%m%d_%H%M%S` OUTPUT=theDAOTokenBalance_${DATE}UTC_all.txt CREATION=theDAOTokenBalance_${DATE}UTC_creation.txt TRANSFER=theDAOTokenBalance_${DATE}UTC_transfer.txt BALANCE=theDAOTokenBalance_${DATE}UTC_balance.txt geth attach << EOF | egrep "^Header|^Data|^Stats|^Footer" > $OUTPUT var theDAOABIFragment = [{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"type":"function"}, {"anonymous":false,"inputs":[{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"CreatedToken","type":"event"}, {"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"Transfer","type":"event"}]; var theDAOAddress = "0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413"; var theDAO = web3.eth.contract(theDAOABIFragment).at(theDAOAddress); var theDAOTokenBalancePreHardForkABI = [{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[],"name":"seal","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"totalAccounts","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"data","type":"uint256[]"}],"name":"fill","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[],"name":"sealed","outputs":[{"name":"","type":"bool"}],"type":"function"},{"inputs":[],"type":"constructor"}]; var theDAOTokenBalancePreHardForkAddress = "0x180826b05452ce96e157f0708c43381fee64a6b8"; var theDAOTokenBalancePreHardForkContract = web3.eth.contract(theDAOTokenBalancePreHardForkABI).at(theDAOTokenBalancePreHardForkAddress); // The DAO created in block 1428757 Apr-30-2016 01:42:58 AM +UTC var creationStartBlock = 1428757; // First The DAO creation event with non-zero extraBalance in block 1520861 May-15-2016 09:00:16 AM +UTC var creationWithExtraBalanceStartBlock = 1520861; // Last The DAO creation event in block 1599205 May-28-2016 08:59:47 AM +UTC var creationEndBlock = 1599205; // First The DAO transfer event in block 1599207 May-28-2016 09:00:07 AM +UTC, but use block above var transferStartBlock = creationEndBlock + 1; // Last The DAO transfer var transferEndBlock = eth.blockNumber; // Pre hard-fork block var preHardForkBlock = 1919999; // Hard-fork block var hardForkBlock = 1920000; // Collect addresses var addresses = {}; // --- Get creation events --- var startBlock = creationStartBlock; var endBlock = creationEndBlock; // Testing // startBlock = creationWithExtraBalanceStartBlock - 5; // endBlock = creationWithExtraBalanceStartBlock + 5; var theDAOCreatedTokenEvent = theDAO.CreatedToken({}, {fromBlock: startBlock, toBlock: endBlock}); console.log("HeaderCreation\tTokenOwner"); var i = 0; theDAOCreatedTokenEvent.watch(function(error, result) { addresses[result.args.to] = 1; i = i + 1; console.log("DataCreation\t" + i + "\t" + result.args.to); }); // --- Get transfer events --- var startBlock = transferStartBlock; var endBlock = transferEndBlock; // Testing // startBlock = transferStartBlock; // endBlock = transferStartBlock + 10; var theDAOTransferEvent = theDAO.Transfer({}, {fromBlock: startBlock, toBlock: endBlock}); console.log("HeaderTransfer\tFrom\tTo"); i = 0; theDAOTransferEvent.watch(function(error, result) { addresses[result.args._from] = 1; addresses[result.args._to] = 1; i = i + 1; console.log("DataTransfer\t" + i + "\t" + result.args._from + "\t" + result.args._to); }); // --- Get balances --- var currentBlock = transferEndBlock; console.log("HeaderBalance\tNumber\tAddress\tPreHardForkDAO\tPreHardForkDAOContract\tPreHardForkDAODiff\tCurrentDAO\tChangeDAO\tPreHardForkETH\tCurrentETH\tChangeETH"); var daosPreHardForkTotal = new BigNumber(0); var daosPreHardForkContractTotal = new BigNumber(0); var daosCurrentTotal = new BigNumber(0); var nonZeroAccounts = new BigNumber(0); i = 0; for (var address in addresses) { i = i + 1; var checkAddress = "0xda0031fab25270778386a2dcac0bb934a288c464"; var daosPreHardFork = theDAO.balanceOf(address, preHardForkBlock); var daosPreHardForkContract = theDAOTokenBalancePreHardForkContract.balanceOf(address); var daosPreHardForkDiff = daosPreHardFork - daosPreHardForkContract; var daosCurrent = theDAO.balanceOf(address, currentBlock); if (daosPreHardFork != 0 || daosPreHardForkContract != 0) { nonZeroAccounts++; } var daosChange = daosCurrent - daosPreHardFork; var ethsPreHardFork = eth.getBalance(address, preHardForkBlock); var ethsCurrent = eth.getBalance(address, currentBlock); var ethsChange = ethsCurrent - ethsPreHardFork; daosPreHardForkTotal = daosPreHardForkTotal.plus(daosPreHardFork); daosPreHardForkContractTotal = daosPreHardForkContractTotal.plus(daosPreHardForkContract); daosCurrentTotal = daosCurrentTotal.plus(daosCurrent); console.log("DataBalance\t" + i + "\t" + address + "\t" + (daosPreHardFork/1e16).toFixed(16) + "\t" + (daosPreHardForkContract/1e16).toFixed(16) + "\t" + (daosPreHardForkDiff/1e16).toFixed(16) + "\t" + (daosCurrent/1e16).toFixed(16) + "\t" + (daosChange/1e16).toFixed(16) + "\t" + (ethsPreHardFork/1e18).toFixed(18) + "\t" + (ethsCurrent/1e18).toFixed(18) + "\t" + (ethsChange/1e18).toFixed(18)); } console.log("Stats\tnonZeroAccounts\t" + nonZeroAccounts); console.log("Stats\tdaosPreHardForkTotal\t" + daosPreHardForkTotal.toPrecision(30) + "\t" + (daosPreHardForkTotal/1e16).toFixed(16)); console.log("Stats\tdaosPreHardForkContractTotal\t" + daosPreHardForkContractTotal.toPrecision(30) + "\t" + (daosPreHardForkContractTotal/1e16).toFixed(16)); console.log("Stats\tdaosCurrentTotal\t" + daosCurrentTotal.toPrecision(30) + "\t" + (daosCurrentTotal/1e16).toFixed(16)); console.log("Footer\tReport generated at " + (new Date()).toGMTString() + " with latest block number " + transferEndBlock); EOF egrep "HeaderCreation|DataCreation|Footer" $OUTPUT > $CREATION egrep "HeaderTransfer|DataTransfer|Footer" $OUTPUT > $TRANSFER egrep "HeaderBalance|DataBalance|Footer|Stats" $OUTPUT > $BALANCE