如何找出以太坊地址是否合同?

bor*_*yer 20 ethereum solidity smartcontracts

Solidity中的地址可以是帐户或合同(或其他事物,例如交易).当我有一个变量x,持有一个地址时,我该如何测试它是否是合同?

(是的,我已经阅读了关于 doc中类型章节)

Man*_*áoz 50

是的,你可以通过使用一些EVM汇编代码来获取地址的代码大小:

function isContract(address addr) returns (bool) {
  uint size;
  assembly { size := extcodesize(addr) }
  return size > 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 关于这个函数如何工作的一些[info](http://ethereum.stackexchange.com/questions/14015/using-evm-assembly-to-get-the-address-code-size/14016#14016) (2认同)
  • 此代码很危险,不再可取,因为它是[hackable](http://web.archive.org/web/20190105222409/https://www.reddit.com/r/ethereum/comments/916xni/how_to_pwn_fomo3d_a_beginners_guide)因为EXTCODESIZE在合约的构造函数中返回0. (2认同)

eth*_*eth 11

isContract使用 EXTCODESIZE的函数的最高投票答案被发现是可破解的。

如果从合约的构造函数调用该函数将返回 false(因为合约尚未部署)。

如果有的话,应该非常小心地使用代码,以避免安全黑客,例如:

https://www.reddit.com/r/ethereum/comments/916xni/how_to_pwn_fomo3d_a_beginners_guide存档

重复

不要使用 EXTCODESIZE 检查来阻止智能合约调用函数。这不是万无一失的,它可以被构造函数调用破坏,因为当构造函数运行时,该地址的 EXTCODESIZE 返回 0。

请参阅欺骗 EXTCODESIZE 返回 0 的合同的示例代码


如果您想确保 EOA 正在调用您的合约,一个简单的方法是require(msg.sender == tx.origin). 但是,阻止合同是一种具有安全性互操作性考虑的反模式

这将需要在实现帐户抽象时重新审视。

  • 应该指出的是,`require(msg.sender == tx.origin)`仅检测函数的调用者是否是EOA,它不能用于检测任何其他第三方合约是否是EOA (例如您想从自己的函数调用的合约)。 (3认同)

fir*_*r96 7

编辑:自从第一次写这个答案以来,Solidity 发生了变化,@manuel-aráoz 有正确的答案。

没有办法可靠地检查地址是否是合同。以太坊的目标之一是平等对待人类和智能合约。这将导致智能合约与人类和其他合约无缝交互的未来。将来可能会改变,但现在任意地址是不明确的。

  • 发送到合约所消耗的gas与发送到地址所消耗的gas完全不同。如果有一个目标以同样的方式对待这两件事,就不会有气体的区别。 (3认同)

小智 7

这不是您可以使用Solidity在合同中查询的内容,但如果您只是想知道某个地址是否包含合同代码,您可以使用您的geth控制台或类似方法检查,例如:

  > eth.getCode("0xbfb2e296d9cf3e593e79981235aed29ab9984c0f")
Run Code Online (Sandbox Code Playgroud)

使用十六进制字符串(此处0xbfb2e296d9cf3e593e79981235aed29ab9984c0f)作为您要查询的地址.这将返回存储在该地址的字节码.

你也可以使用一个blockchain扫描器找到合同的源代码,在该地址,例如在ecsol库上所显示etherscan.io.