Solidity

用地址數組構造合約

  • January 10, 2017

如果我錯了,請糾正我,但我知道您不能用字元串數組初始化契約,因為它是動態類型,但我可以用固定類型初始化契約嗎?特別是地址數組。

另外,如果我嘗試通過字節碼進行部署,這將如何序列化?

這是 Whitehats 使用的一種解決方案,將檢索到的 ETC 分發給乙太坊經典鏈上的 DAO 代幣持有者。

來自https://github.com/BitySA/whetcwithdraw/blob/master/daobalance/dao_balance_snapshot.sol

// This contract publishes the balances of the DAO at the moment of the hardfork
// After the deployment of the contract the function fill is called many times
// in order to fill the balance of each account.


contract DAOBalanceSnapShot {

   uint constant D160 = 0x10000000000000000000000000000000000000000;

   mapping (address => uint) public balanceOf;

   address public owner;

   function DAOBalanceSnapShot() {
       owner = msg.sender;
   }


   uint public totalSupply;
   uint public totalAccounts;
   bool public sealed;

   // The 160 LSB is the address of the balance
   // The 96 MSB is the balance of that address.
   function fill(uint[] data) {
       if ((msg.sender != owner)||(sealed))
           throw;

       for (uint i=0; i<data.length; i++) {
           address a = address( data[i] & (D160-1) );
           uint amount = data[i] / D160;
           if (balanceOf[a] == 0) {   // In case it's filled two times, it only increments once
               totalAccounts ++;
               balanceOf[a] = amount;
               totalSupply += amount;
           }
       }
   }

   function seal() {
       if ((msg.sender != owner)||(sealed))
           throw;

       sealed= true;
   }
}

您可以看到地址和余額被編碼為數據數組uint256

在此解決方案中,建構子不用於初始化地址(和余額)數組。但是在構造之後,該fill(...)函式被反複呼叫以構造balanceOf地址到餘額的映射。在所有必需的餘額都被填滿後,seal()呼叫該函式以指示余額已全部被填滿。

當超過 11,000 項地址和余額需要填充必要的數據時,這種“填充”數據的方法是解決方案,因為數據不會適合單個建構子呼叫。

參考:如何將我的 The DAO 代幣轉換為 Ethereum Classic 鏈上的乙太幣?


用一個例子更新

這是一個例子:

pragma solidity ^0.4.4;

contract AddressArray {

   address[] addresses;

   function AddressArray(address[] addresses_) {
       for (uint i = 0; i < addresses_.length; i++) {
           addresses.push(addresses_[i]);
       }
   }

   function getNumberOfAddresses() constant returns (uint) {
       return addresses.length;
   }

   function getAddress(uint i) constant returns (address) {
       return addresses[i];
   }
}

我將使用 Browser Solidity 建構合約,並使用以下地址作為參數:

$$ “0x000d1009bd8f0b1301cc5edc28ed1222a3ce671e”, “0x0014060ff383c9b21c6840a3b14aab06741e5c49”, “0x0020017ba4c67f76c76b1af8c41821ee54f37171”, “0x0036f6addb6d64684390f55a92f0f4988266901b”, “0x004e64833635cd1056b948b57286b7c91e62731c” $$

這是 Browser Solidity 螢幕,顯示使用地址參數數組成功部署合約:

在此處輸入圖像描述

這是來自 Browser Solidity 的字節碼數據:

606060405234610000576040516101f83803806101f8833981016040528080518201919060200150505b6000600090505b81518110156100f357600080548060010182818154818355818115116100825781836000526020600020918201910161008191905b8082111561007d576000816000905550600101610065565b5090565b5b505050916000526020600020900160005b848481518110156100005790602001906020020151909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690836c01000000000000000000000000908102040217905550505b8080600101915050610030565b5b50505b60f4806101046000396000f360606040526000357c0100000000000000000000000000000000000000000000000000000000900480632e61319d146040578063b93f9b0a146060575b6000565b34600057604a60a4565b6040518082815260200191505060405180910390f35b346000576078600480803590602001909190505060b2565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600060008054905090505b90565b60006000828154811015600057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1650505b919050

在將合約部署到我的開發區塊鏈之前,我打開debug.verbosity(5)以查看原始格式的交易。這是數據:

I0110 15:40:29.061385 core/tx_pool.go:542] 促進排隊交易:TX(4856cf602e31c38000279f3fb1bdf3f13c475fac4e35f9cc67811e34ef0ceda4) 契約:false 來自:000d1009718f0b2301cc5

$$ contract creation $$ Nonce:17 GasPrice:20000000000 GasLimit 281531 值:0 數據:0x606060405234610000576040516101f83803806101f8833981016040528080518201919060200150505b6000600090505b81518110156100f357600080548060010182818154818355818115116100825781836000526020600020918201910161008191905b8082111561007d576000816000905550600101610065565b5090565b5b505050916000526020600020900160005b848481518110156100005790602001906020020151909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690836c01000000000000000000000000908102040217905550505b8080600101915050610030565b5b50505b60f4806101046000396000f360606040526000357c0100000000000000000000000000000000000000000000000000000000900480632e61319d146040578063b93f9b0a146060575b6000565b34600057604a60a4565b6040518082815260200191505060405180910390f35b346000576078600480803590602001909190505060b2565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600060008054905090505b90565b60006000828154811015600057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffff10560505b91000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000d1009bd8f0b1301cc5edc28ed1222a3ce671e0000000000000000000000000014060ff383c9b21c6840a3b14aab06741e5c490000000000000000000000000020017ba4c67f76c76b1af8c41821ee54f371710000000000000000000000000036f6addb6d64684390f55a92f0f4988266901b000000000000000000000000004e64833635cd1056b948b57286b7c91e62731c

在上面的數據中,我用粗體突出了表示合約部署期間參數的附加字節碼。

如果您打算通過字節碼進行部署,現在讓我們對您需要建構的字節碼進行逆向工程。

這是已部署字節碼中的粗體數據,分離出來:

0000000000000000000000000000000000000000000000000000000000000020 // 0x20 = 32. This is probably the offset to the start of the array data
0000000000000000000000000000000000000000000000000000000000000005 // There are five items in the array
000000000000000000000000000d1009bd8f0b1301cc5edc28ed1222a3ce671e // 1st address
0000000000000000000000000014060ff383c9b21c6840a3b14aab06741e5c49 // 2nd address
0000000000000000000000000020017ba4c67f76c76b1af8c41821ee54f37171 // 3rd address
0000000000000000000000000036f6addb6d64684390f55a92f0f4988266901b // 4th address
000000000000000000000000004e64833635cd1056b948b57286b7c91e62731c // 5th address

請參閱下面的第二個連結以嘗試對參數格式進行逆向工程,包括偏移量。

讓我們嘗試另一種參數組合

這是另一個帶有額外建構子參數的契約:

pragma solidity ^0.4.4;

contract AddressArray {

   address[] addresses;

   function AddressArray(uint dummy1, address[] addresses_, uint dummy2) {
       for (uint i = 0; i < addresses_.length; i++) {
           addresses.push(addresses_[i]);
       }
   }

   function getNumberOfAddresses() constant returns (uint) {
       return addresses.length;
   }

   function getAddress(uint i) constant returns (address) {
       return addresses[i];
   }
}

我使用 Browser Solidity 的以下參數部署了合約:

123,

$$ “0x000d1009bd8f0b1301cc5edc28ed1222a3ce671e”, “0x0014060ff383c9b21c6840a3b14aab06741e5c49” $$, 456

這是來自 Browser Solidity 的字節碼:

6060604052346100005760405161020c38038061020c833981016040528080519060200190919080518201919060200180519060200190919050505b6000600090505b825181101561010557600080548060010182818154818355818115116100945781836000526020600020918201910161009391905b8082111561008f576000816000905550600101610077565b5090565b5b505050916000526020600020900160005b858481518110156100005790602001906020020151909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690836c01000000000000000000000000908102040217905550505b8080600101915050610042565b5b505050505b60f4806101186000396000f360606040526000357c0100000000000000000000000000000000000000000000000000000000900480632e61319d146040578063b93f9b0a146060575b6000565b34600057604a60a4565b6040518082815260200191505060405180910390f35b346000576078600480803590602001909190505060b2565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600060008054905090505b90565b60006000828154811015600057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b91905056

這是geth事務跟踪數據,再次以粗體顯示附加參數字節碼數據:

0x6060604052346100005760405161020c38038061020c833981016040528080519060200190919080518201919060200180519060200190919050505b6000600090505b825181101561010557600080548060010182818154818355818115116100945781836000526020600020918201910161009391905b8082111561008f576000816000905550600101610077565b5090565b5b505050916000526020600020900160005b858481518110156100005790602001906020020151909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690836c01000000000000000000000000908102040217905550505b8080600101915050610042565b5b505050505b60f4806101186000396000f360606040526000357c0100000000000000000000000000000000000000000000000000000000900480632e61319d146040578063b93f9b0a146060575b6000565b34600057604a60a4565b6040518082815260200191505060405180910390f35b346000576078600480803590602001909190505060b2565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600060008054905090505b90565b60006000828154811015600057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b91905056000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000001c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d1009bd8f0b1301cc5edc28ed1222a3ce671e0000000000000000000000000014060ff383c9b21c68406741a

這是參數數據,已解碼:

000000000000000000000000000000000000000000000000000000000000007b // new BigNumber("7b",16) = 123
0000000000000000000000000000000000000000000000000000000000000060 // new BigNumber("60",16) = 96 or 3 x 32. This is the offset of the second parameter.
00000000000000000000000000000000000000000000000000000000000001c8 // new BigNumber("1c8",16) = 456
0000000000000000000000000000000000000000000000000000000000000002 // 2 array items
000000000000000000000000000d1009bd8f0b1301cc5edc28ed1222a3ce671e // 1st address
0000000000000000000000000014060ff383c9b21c6840a3b14aab06741e5c49 // 2nd address

也可以看看:

引用自:https://ethereum.stackexchange.com/questions/11187