以太坊合约地址计算
Posted mutourend
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了以太坊合约地址计算相关的知识,希望对你有一定的参考价值。
1. 引言
以太坊创建合约的方式有2种:
- 1)由EOA账号直接创建合约
- 2)由其它智能合约创建智能合约
- 2.1)通过
CREATE(0xf0)
opcode - 2.2)通过
CREATE2(0xf5)
opcode
// SPDX-License-Identifier: MIT pragma solidity 0.8.7; contract OpCreates function opCreate(bytes memory bytecode, uint length) public returns(address) address addr; assembly addr := create(0, 0xa0, length) sstore(0x0, addr) return addr; function opCreate2(bytes memory bytecode, uint length) public returns(address) address addr; assembly addr := create2(0, 0xa0, length, 0x2) sstore(0x0, addr) return addr; function sendValue() public payable uint bal; assembly bal := add(bal,callvalue()) sstore(0x1, bal) function opCreateValue(bytes memory bytecode, uint length) public payable returns(address) address addr; assembly addr := create(500, 0xa0, length) sstore(0x0, addr) return addr; function opCreate2Value(bytes memory bytecode, uint length) public payable returns(address) address addr; assembly addr := create2(300, 0xa0, length, 0x55555) sstore(0x0, addr) return addr;
- 2.1)通过
2. 由EOA账号直接创建的合约——合约地址计算
由EOA账号直接创建的合约——合约地址计算规则,根据pyethereum有:
try:
from Crypto.Hash import keccak
sha3_256 = lambda x: keccak.new(digest_bits=256, data=x).digest()
except:
import sha3 as _sha3
sha3_256 = lambda x: _sha3.sha3_256(x).digest()
def mk_contract_address(sender, nonce):
return sha3(rlp.encode([normalize_address(sender), nonce]))[12:]
即采用sender-and-nonce-hash方式来计算合约地址。
以太坊合约的地址是根据creator地址(sender
) 和 该creator已发送的交易数(nonce
)经RLP编码再采用Keccak-256哈希运算 确定性计算而来的:【下述示例应进一步拓展为支持nonce最大值
2
64
2^64
264】
// Solidity 0.8及以上
function addressFrom(address _origin, uint _nonce) public pure returns (address)
bytes memory data;
if (_nonce == 0x00) data = abi.encodePacked(byte(0xd6), byte(0x94), _origin, byte(0x80));
else if (_nonce <= 0x7f) data = abi.encodePacked(byte(0xd6), byte(0x94), _origin, byte(_nonce));
else if (_nonce <= 0xff) data = abi.encodePacked(byte(0xd7), byte(0x94), _origin, byte(0x81), uint8(_nonce));
else if (_nonce <= 0xffff) data = abi.encodePacked(byte(0xd8), byte(0x94), _origin, byte(0x82), uint16(_nonce));
else if (_nonce <= 0xffffff) data = abi.encodePacked(byte(0xd9), byte(0x94), _origin, byte(0x83), uint24(_nonce));
else data = abi.encodePacked(byte(0xda), byte(0x94), _origin, byte(0x84), uint32(_nonce));
return address(keccak256(data));
// Solidity 0.6
function addressFrom(address _origin, uint _nonce) public pure returns (address)
bytes memory data;
if (_nonce == 0x00) data = abi.encodePacked(byte(0xd6), byte(0x94), _origin, byte(0x80));
else if (_nonce <= 0x7f) data = abi.encodePacked(byte(0xd6), byte(0x94), _origin, uint8(_nonce));
else if (_nonce <= 0xff) data = abi.encodePacked(byte(0xd7), byte(0x94), _origin, byte(0x81), uint8(_nonce));
else if (_nonce <= 0xffff) data = abi.encodePacked(byte(0xd8), byte(0x94), _origin, byte(0x82), uint16(_nonce));
else if (_nonce <= 0xffffff) data = abi.encodePacked(byte(0xd9), byte(0x94), _origin, byte(0x83), uint24(_nonce));
else data = abi.encodePacked(byte(0xda), byte(0x94), _origin, byte(0x84), uint32(_nonce));
return address(uint256(keccak256(data)));
可借助汇编代码进一步优化以节约gas费:
// Solidity 0.8及以上
function addressFrom(address _origin, uint _nonce) external pure returns (address _address)
bytes memory data;
if(_nonce == 0x00) data = abi.encodePacked(bytes1(0xd6), bytes1(0x94), _origin, bytes1(0x80));
else if(_nonce <= 0x7f) data = abi.encodePacked(bytes1(0xd6), bytes1(0x94), _origin, uint8(_nonce));
else if(_nonce <= 0xff) data = abi.encodePacked(bytes1(0xd7), bytes1(0x94), _origin, bytes1(0x81), uint8(_nonce));
else if(_nonce <= 0xffff) data = abi.encodePacked(bytes1(0xd8), bytes1(0x94), _origin, bytes1(0x82), uint16(_nonce));
else if(_nonce <= 0xffffff) data = abi.encodePacked(bytes1(0xd9), bytes1(0x94), _origin, bytes1(0x83), uint24(_nonce));
else data = abi.encodePacked(bytes1(0xda), bytes1(0x94), _origin, bytes1(0x84), uint32(_nonce));
bytes32 hash = keccak256(data);
assembly
mstore(0, hash)
_address := mload(0)
// Solidity 0.6
function addressFrom(address _origin, uint _nonce) public pure returns (address _address)
bytes memory data;
if(_nonce == 0x00) data = abi.encodePacked(byte(0xd6), byte(0x94), _origin, byte(0x80));
else if(_nonce <= 0x7f) data = abi.encodePacked(byte(0xd6), byte(0x94), _origin, uint8(_nonce));
else if(_nonce <= 0xff) data = abi.encodePacked(byte(0xd7), byte(0x94), _origin, byte(0x81), uint8(_nonce));
else if(_nonce <= 0xffff) data = abi.encodePacked(byte(0xd8), byte(0x94), _origin, byte(0x82), uint16(_nonce));
else if(_nonce <= 0xffffff) data = abi.encodePacked(byte(0xd9), byte(0x94), _origin, byte(0x83), uint24(_nonce));
else data = abi.encodePacked(byte(0xda), byte(0x94), _origin, byte(0x84), uint32(_nonce));
bytes32 hash = keccak256(data);
assembly
mstore(0, hash)
_address := mload(0)
3. 由其它智能合约创建合约——合约地址计算
在EIP-1014:Skinny CREATE2中,额外引入了新的opcode CREATE2(0xf5)
来创建智能合约。CREATE2(0xf5)
与CREATE(0xf0)
的工作模式相同,只是CREATE(0xf0)
计算合约地址采用sender-and-nonce-hash方式,而CREATE2(0xf5)
采用合约地址计算规则为:
keccak256( 0xff ++ senderAddress ++ salt ++ keccak256(init_code))[12:]
参考资料
[1] How to calculate an Ethereum Contract’s address during its creation using the Solidity language?
[2] How is the address of an Ethereum contract computed?
以上是关于以太坊合约地址计算的主要内容,如果未能解决你的问题,请参考以下文章