以太坊合约地址计算

这篇具有很好参考价值的文章主要介绍了以太坊合约地址计算。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 引言

前序博客有:

  • 以太坊proxy合约

以太坊合约实现中,为实现可升级性、地址一致性、state和data 与 合约逻辑 分离,proxy承担了重要的角色。在proxy合约中,合约部署主要采用过CREATE(0xf0)CREATE2(0xf5) opcode。

以太坊创建合约的方式有2种:

  • 1)由EOA账号直接创建合约
  • 2)由其它智能合约创建智能合约
    • 2.1)通过CREATE(0xf0) opcode:合约地址由keccak256(sender, nonce)确定。
      CREATE方式简单,但存在不同网络重放问题,详细见Wintermute hack on Optimism攻击。
    • 2.2)通过CREATE2(0xf5) opcode:合约地址由keccak256(0xff, sender, salt, keccak256(bytecode))确定。引入0xff是为了避免CREATE2创建的合约地址与CREATE的发生碰撞。因为0xff byte,作为RLP编码的starting byte时,对应的数据结构长度将为PB(petabytes)级,这在以太坊合约及数据结构中是不可能达到的。
      借助CREATE2,可能可通过Metamorphosis Smart Contract Pattern,将不同的bytecode部署到同一地址。详细参看Metamorphosis Smart Contracts using CREATE2。
      为避免不同链之间的重放,推荐使用基于old salt和unique data(如inputs或unique data hash)来派生new salt:bytes20 newSalt = bytes20(keccak256(abi.encodePacked(_initializerData, _salt)));
    // 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. 由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?
[3] 2023年4月博客 Deep Dive into Smart Contract Proxies: Variants, CREATE vs. CREATE2, and Security Considerations文章来源地址https://www.toymoban.com/news/detail-785944.html

到了这里,关于以太坊合约地址计算的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java SDK部署和调用FISCO BCOS区块链智能合约

    使用WeBASE合约管理导出Java项目 启动FISCO节点和webase-front,部署服务详情可参考官方文档: link 1.编写智能合约 一个简单的例子: Table 合约:该合约负责维护候选人的信息。每个候选人都有一个唯一的标识符sign_key,以及与之相关联的其他属性,包括活动名称activity_name、参与

    2024年03月22日
    浏览(43)
  • 区块链DAPP开发 以太坊智能合约框架有哪些

    Truffle 是一个在以太坊进行 DApp 开发的世界级开发环境、测试框架。 使用 Truffle 开发有一以下优点: 内置智能合约编译,链接,部署和二进制(文件)管理。 可快速开发自动化智能合约测试框架。 可脚本化、可扩展的部署和迁移框架。 可管理多个不同的以太坊网络,可部署

    2024年02月02日
    浏览(34)
  • java-sdk-demo 测试自己部署的合约(PerformanceXXX.java)区块链性能测试

    祝大家龙年快乐呀! 最近一直在做区块链的性能测试,我发现目前很多文档里面,都没有仔细介绍怎么测试自己的合约,我在自己做实验期间遇到了很多问题,网上没有找到答案,所以我成功之后,就自己遇到的一些问题写一个文档,希望对大家有一些帮助。 一、我们将s

    2024年02月03日
    浏览(22)
  • 【区块链】以太坊Solidity编写一个简单的Hello World合约

    熟悉一门语言得从Hello World! 开始,因为这是最简单的一个输出形式。 我们先在contracts目录下建立一个helloworld.sol文件 进入编辑 保存退出 在migrations下新建一个部署合约的js文件:3_initial_migration.js 名字可以变动 接下来在test中使用js调用智能合约 在另一个窗口打开ganache 运行智

    2024年02月15日
    浏览(55)
  • 【区块链技术开发】十个比较流行的以太坊智能合约开发框架

    专栏:【区块链技术开发】 前期文章: 【区块链技术开发】剖析区块链Ganache模拟器工具及其智能合约部署区块链的查询方式 【区块链技术开发】基于Web3.js以太坊网络上的智能合约的交互及其应用 【区块链技术开发】OpenZeppelin智能合约库:提高智能合约的安全性和可靠性,

    2024年02月02日
    浏览(49)
  • 【区块链 | 智能合约】Ethereum源代码(10)- 以太坊Downloader源码分析

    上一节分析到Fetcher用于同步网络节点的新区块和新的交易数据,如果新区块和本地最新的区块相隔距离较远,说明本地区块数据太旧,Fetcher就不会同步这些区块。这时候就要借助Downloader来同步完整的区块数据。 一,启动Downloader handler 初始化的时候会进行Downloader的初始化:

    2024年02月15日
    浏览(33)
  • 【区块链 | 智能合约】Ethereum源代码(11)- 以太坊核心BlockChain源码分析

    前面几节都在分析以太坊的通信协议,怎么广播,怎么同步,怎么下载。这一节讲讲以太坊的核心模块BlockChain,也就是以太坊的区块链。 一,BlockChain的初始化 Ethereum服务初始化func init() 的时候会调用core.SetupGenesisBlock来加载创始区块。顾名思义,创始区块就是以太坊区块链中

    2024年02月08日
    浏览(32)
  • 区块链钱包“BTC,TRX,ETH”地址生成、助记词导入、keyStron文件生成等功能

    #最近闲着没事做,然后看听到说什么BTC疯涨,这类的小道消息。          哦豁~,这一下就让我觉得非常好奇,说,他们这些东西是怎样在链上存在的呢,然后他们那个一串串的地址又是啥,imtoken钱包又是怎么实现的呢。         根据以上疑问,我自己去研究,自己

    2024年04月14日
    浏览(37)
  • 《区块链原理与技术》学习笔记(四) ——以太坊的基本架构、账户模型和智能合约

    《区块链原理与技术》学习笔记 第四部分 三、以太坊 1. 以太坊简介 1.1 以太坊发展的阶段 1.2 以太坊与比特币对比 2. 以太坊的基本架构及原理 2.1 基本概念 2.2 状态转移 2.3 基本架构 3. 账户模型与转账 3.1 账户模型 4. 智能合约 4.1 合约账户与数据存储 4.2 驱动智能合约 以太坊

    2024年02月13日
    浏览(37)
  • 以太坊 – 部署智能合约到Ganache

    目录 1. Ganache本地区块链 1.1 主界面 1.2 设置 2. 开发智能合约 2.1 初始化项目 2.2 添加package.json文件 2.3 添加智能合约源文件 2.4 编译项目 3. 部署智能合约到Ganache 3.1 更新配置文件 3.2 创建迁移脚本  3.3 执行迁移命令 首先启动Ganache,创建本地的以太坊区块链网络。 本地

    2024年02月16日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包