【发布时间】:2016-10-05 07:00:22
【问题描述】:
Solidity 中的地址可以是账户或合约(或其他事物,例如交易)。当我有一个变量 x ,持有一个地址时,我如何测试它是否是一个合约?
(是的,我已经阅读了文档中的chapter on types)
【问题讨论】:
标签: ethereum solidity smartcontracts
Solidity 中的地址可以是账户或合约(或其他事物,例如交易)。当我有一个变量 x ,持有一个地址时,我如何测试它是否是一个合约?
(是的,我已经阅读了文档中的chapter on types)
【问题讨论】:
标签: ethereum solidity smartcontracts
isContract 函数获得最高票数的答案被发现是可破解的。如果从合约的构造函数调用该函数将返回 false(因为合约尚未部署)。
应该非常小心地使用代码,以避免安全黑客攻击,例如:
https://www.reddit.com/r/ethereum/comments/916xni/how_to_pwn_fomo3d_a_beginners_guide (archive)
致repeat:
不要使用 EXTCODESIZE 检查来阻止智能合约调用函数。这不是万无一失的,它可以被构造函数调用破坏,因为在构造函数运行时,该地址的 EXTCODESIZE 返回 0。
请参阅 sample code 以了解欺骗 EXTCODESIZE 返回 0 的合约。
如果您想确保 EOA 正在调用您的合约,一个简单的方法是 require(msg.sender == tx.origin)。但是,阻止合同是 anti-pattern 与 security 和 interoperability 考虑因素。
require(msg.sender == tx.origin) 在实现帐户抽象时需要重新访问。
正如@Luke 在评论中指出的那样,没有没有通用的链上方法来了解被调用者。如果您想“调用”一个地址,没有通用的方法可以确定该地址是合约、EOA 还是可以部署新合约的地址,或者它是否是 CREATE2 地址。
一种适用于某些被调用者的非通用方式:您可以在链上进行映射,以存储已知 EOA 或合约的地址。 (请记住,对于没有任何链上历史记录的地址,您无法知道它是 EOA 还是可以部署合约的地址。)
【讨论】:
require(msg.sender == tx.origin)只检测函数的调用者是否为EOA,不能用于检测任何其他第三方合约是否为EOA(如作为你想从你自己的函数中调用的合约)。
<address>.code.size 的solidity(无需组装)。人们也需要识别这种形式。 (我可能语法错误,我现在不在电脑附近。)
如果您手头有信息,您可以做什么。 如果交易发件人地址为空或未被占用,那么您可以判断该地址是合约账户还是 EOA(外部拥有的账户)。 即在网络上发送创建合约交易时,交易中的接收地址为空/未使用。
来自github的参考: https://github.com/ethereum/go-ethereum/wiki/Contracts-and-Transactions
希望这会有所帮助。
【讨论】:
简答:
require(tx.origin == msg.sender);
tx.origin 是对发起这个串行函数调用的原始地址的引用,而 msg.sender 是直接调用目标函数的地址。这意味着,tx.origin 必须是人类,msg.sender 可以是合约或人类。因此,如果有人通过合约给你打电话,那么 msg.sender 就是一个不同于 tx.origin 的合约地址。
我知道大多数合同可能会使用@Manuel Aráoz 的代码,该代码在大多数情况下都有效。但是如果你在合约的构造函数中调用一个函数,extcodesize 将返回 0,这会导致 isContract 检查失败。
注意:如果您不清楚它代表什么,请勿在其他情况下使用 tx.origin,因为 .
【讨论】:
编辑:自从首次编写此答案以来,Solidity 发生了变化,@manuel-aráoz 有正确的答案。
没有办法检查地址是否是合约。以太坊的目标之一是让人类和智能合约都得到平等对待。这导致了智能合约与人类和其他合约无缝交互的未来。未来可能会发生变化,但目前任意地址是不明确的。
【讨论】:
这不是您可以使用 Solidity 从合约中查询的内容,但如果您只是想知道某个地址是否包含合约代码,您可以使用您的 geth 控制台或类似的控制台进行检查,例如:
> eth.getCode("0xbfb2e296d9cf3e593e79981235aed29ab9984c0f")
使用十六进制字符串(此处为0xbfb2e296d9cf3e593e79981235aed29ab9984c0f)作为您要查询的地址。这将返回存储在该地址的字节码。
您还可以使用区块链扫描仪在该地址查找合约的源代码,例如the ecsol library,如etherscan.io 所示。
【讨论】: