Etherscan显示合约的创建代码还是运行时代码?

本文探讨了Etherscan上已部署和验证的智能合约显示的字节码内容。通过实验对比,发现Etherscan显示的并非仅是运行时字节码,而是完整的字节码(创建代码+运行时代码),并附加构造函数参数(如果存在)。此外,未验证的合约在Etherscan上仅显示运行时字节码。

这将是一篇关于 Etherscan 如何显示已部署和验证的智能合约字节码的一些发现的简短文章。

在以太坊区块链上部署合约之后,我们确切地知道创建代码(初始化代码)会被执行,并返回运行时字节码,然后将其存储在链上。

必须注意的是,只有智能合约的运行时字节码才会被存储在链上,以便进一步执行智能合约。

但是,这里有一个快速的问题:

当我们在以太坊上部署一个智能合约并在 Etherscan 上验证它时,附加到已验证合约上的字节码到底是什么?

这个问题的非常直观的答案是 运行时字节码,因为这是存储在链上的字节码部分。因此,很容易假设 Etherscan 仅显示运行时字节码。

好吧,情况似乎并非如此。

所以问题仍然存在 - 我们在 Etherscan 上看到的字节码到底是什么?

  • 它是完整的字节码,即(创建代码 + 运行时代码)吗?
  • 或者,它只是 运行时代码 吗?
  • 或者,它是 运行时代码 + 构造函数参数 吗?

让我们做一个快速实验来弄清楚。

一个快速实验

我们将要部署 2 个不同的合约:

  • 第一个没有任何构造函数参数,以及
  • 第二个带有构造函数参数

首次部署:没有构造函数参数

我们使用以下测试合约 👇

// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.17;

/**
 * @title Test
 * @dev Sets and Gets a uint variable called Pointer
 */
contract Test{

    uint256 public pointery;

    constructor() {
        pointery = 100;
    }

    function setPointer(uint256 _num) public {
        pointery = _num;
    }

    /**
     * @dev Return owner address
     * @return address of owner
     */
    function getPointer() external view returns (uint256) {
        return pointery;
    }
}

没有构造函数参数的测试合约

Goerli 部署地址

实际创建代码

创建代码

608060405234801561001057600080fd5b50606460008190555061017f806100286000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80632f5f3b3c14610046578063a32a3ee414610064578063acfee28314610082575b600080fd5b61004e61009e565b60405161005b91906100d0565b60405180910390f35b61006c6100a4565b60405161007991906100d0565b60405180910390f35b61009c6004803603810190610097919061011c565b6100ad565b005b60005481565b60008054905090565b8060008190555050565b6000819050919050565b6100ca816100b7565b82525050565b60006020820190506100e560008301846100c1565b92915050565b600080fd5b6100f9816100b7565b811461010457600080fd5b50565b600081359050610116816100f0565b92915050565b600060208284031215610132576101316100eb565b5b600061014084828501610107565b9150509291505056fea264697066735822122095cb79f37fbcae031f3faea184aa57e0c8cd49ed26e7a6d17a48cf3858e56d9f64736f6c63430008110033

实际运行时代码

运行时字节码

608060405234801561001057600080fd5b50600436106100415760003560e01c80632f5f3b3c14610046578063a32a3ee414610064578063acfee28314610082575b600080fd5b61004e61009e565b60405161005b91906100d0565b60405180910390f35b61006c6100a4565b60405161007991906100d0565b60405180910390f35b61009c6004803603810190610097919061011c565b6100ad565b005b60005481565b60008054905090565b8060008190555050565b6000819050919050565b6100ca816100b7565b82525050565b60006020820190506100e560008301846100c1565b92915050565b600080fd5b6100f9816100b7565b811461010457600080fd5b50565b600081359050610116816100f0565b92915050565b600060208284031215610132576101316100eb565b5b600061014084828501610107565b9150509291505056fea264697066735822122095cb79f37fbcae031f3faea184aa57e0c8cd49ed26e7a6d17a48cf3858e56d9f64736f6c6343000811003300

合约验证后 Etherscan 的字节码

608060405234801561001057600080fd5b50606460008190555061017f806100286000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80632f5f3b3c14610046578063a32a3ee414610064578063acfee28314610082575b600080fd5b61004e61009e565b60405161005b91906100d0565b60405180910390f35b61006c6100a4565b60405161007991906100d0565b60405180910390f35b61009c6004803603810190610097919061011c565b6100ad565b005b60005481565b60008054905090565b8060008190555050565b6000819050919050565b6100ca816100b7565b82525050565b60006020820190506100e560008301846100c1565b92915050565b600080fd5b6100f9816100b7565b811461010457600080fd5b50565b600081359050610116816100f0565b92915050565b600060208284031215610132576101316100eb565b5b600061014084828501610107565b9150509291505056fea264697066735822122095cb79f37fbcae031f3faea184aa57e0c8cd49ed26e7a6d17a48cf3858e56d9f64736f6c63430008110033

第二次部署:带有构造函数参数

我们使用以下测试合约 👇 并传递 1000 作为参数。

/**
 *Submitted for verification at Etherscan.io on 2023-02-15
*/

// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.17;

/**
 * @title Test
 * @dev Sets and Gets a uint variable called Pointer
 */
contract Test{

    uint256 public pointer;

    constructor(uint256 _num) {
        pointer = _num;
    }

    function setPointer(uint256 _num) public {
        pointer = _num;
    }

    /**
     * @dev Return owner address
     * @return address of owner
     */
    function getPointer() external view returns (uint256) {
        return pointer;
    }
}

带有 1 个构造函数参数的测试合约

Goerli 部署地址

实际创建代码

0x608060405234801561001057600080fd5b506040516102353803806102358339818101604052810190610032919061007a565b80600081905550506100a7565b600080fd5b6000819050919050565b61005781610044565b811461006257600080fd5b50565b6000815190506100748161004e565b92915050565b6000602082840312156100905761008f61003f565b5b600061009e84828501610065565b91505092915050565b61017f806100b66000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80632f5f3b3c14610046578063a32a3ee414610064578063acfee28314610082575b600080fd5b61004e61009e565b60405161005b91906100d0565b60405180910390f35b61006c6100a4565b60405161007991906100d0565b60405180910390f35b61009c6004803603810190610097919061011c565b6100ad565b005b60005481565b60008054905090565b8060008190555050565b6000819050919050565b6100ca816100b7565b82525050565b60006020820190506100e560008301846100c1565b92915050565b600080fd5b6100f9816100b7565b811461010457600080fd5b50565b600081359050610116816100f0565b92915050565b600060208284031215610132576101316100eb565b5b600061014084828501610107565b9150509291505056fea2646970667358221220e258c2c50f60615be13c1352bb92ad8365dcb6b971ca21882a504f1beb4167fc64736f6c6343000811003300000000000000000000000000000000000000000000000000000000000003e8

实际运行时代码

608060405234801561001057600080fd5b50600436106100415760003560e01c80632f5f3b3c14610046578063a32a3ee414610064578063acfee28314610082575b600080fd5b61004e61009e565b60405161005b91906100d0565b60405180910390f35b61006c6100a4565b60405161007991906100d0565b60405180910390f35b61009c6004803603810190610097919061011c565b6100ad565b005b60005481565b60008054905090565b8060008190555050565b6000819050919050565b6100ca816100b7565b82525050565b60006020820190506100e560008301846100c1565b92915050565b600080fd5b6100f9816100b7565b811461010457600080fd5b50565b600081359050610116816100f0565b92915050565b600060208284031215610132576101316100eb565b5b600061014084828501610107565b9150509291505056fea2646970667358221220e258c2c50f60615be13c1352bb92ad8365dcb6b971ca21882a504f1beb4167fc64736f6c6343000811003300

合约验证后 Etherscan 的字节码

608060405234801561001057600080fd5b506040516102353803806102358339818101604052810190610032919061007a565b80600081905550506100a7565b600080fd5b6000819050919050565b61005781610044565b811461006257600080fd5b50565b6000815190506100748161004e565b92915050565b6000602082840312156100905761008f61003f565b5b600061009e84828501610065565b91505092915050565b61017f806100b66000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80632f5f3b3c14610046578063a32a3ee414610064578063acfee28314610082575b600080fd5b61004e61009e565b60405161005b91906100d0565b60405180910390f35b61006c6100a4565b60405161007991906100d0565b60405180910390f35b61009c6004803603810190610097919061011c565b6100ad565b005b60005481565b60008054905090565b8060008190555050565b6000819050919050565b6100ca816100b7565b82525050565b60006020820190506100e560008301846100c1565b92915050565b600080fd5b6100f9816100b7565b811461010457600080fd5b50565b600081359050610116816100f0565b92915050565b600060208284031215610132576101316100eb565b5b600061014084828501610107565b9150509291505056fea2646970667358221220e258c2c50f60615be13c1352bb92ad8365dcb6b971ca21882a504f1beb4167fc64736f6c6343000811003300000000000000000000000000000000000000000000000000000000000003e8

发现

在上述部署和实际字节码与 Etherscan 字节码的字节码比较之后,以下是我遇到的发现:

  1. 虽然运行时代码是唯一存储在链上的字节码部分,但 Etherscan 不仅仅显示运行时代码。
  2. 如果存在构造函数参数,Etherscan 会显示附加了构造函数参数的智能合约的整个字节码(初始化代码 + 运行时代码)。

因此,从技术上讲,Etherscan 显示:

初始化代码(在合约部署期间执行)+ 运行时代码(存储在链上的部分)+ 构造函数参数

一个额外的细节:尚未在 Etherscan 上验证的智能合约的字节码只是运行时字节码。

  • 原文链接: decipherclub.com/does-et...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
decipherclub
decipherclub
江湖只有他的大名,没有他的介绍。