将数据传输到EOA或合约
当你的交易包含+data+时,它很可能是发送到合约地址的。这并不意味着你无法向EOA发送+data+。事实上,你可以做到这一点。但是,在这种情况下,data+的解释取决于你用来访问EOA的钱包。大多数钱包会忽略它们控制的EOA交易中收到的任何+data。将来,可能会出现允许钱包以合约的方式解释+data+编码的标准,从而允许交易调用在用户钱包内运行的函数。关键的区别在于,与合约执行不同,EOA对data的任何解释都不受以太坊共识规则的约束。
现在,假设你的交易是向合约地址提供 data。在这种情况下,data 将被EVM解释为 函数调用 function invocation,调用指定的函数并将任何编码参数传递给该函数。
发送到合约的 data 是一个十六进制序列化的编码:
函数选择器(function selector)
函数_prototype_的Keccak256哈希的前4个字节。这使EVM能够明确地识别你希望调用的功能。
函数参数
函数的参数,根据EVM定义的各种基本类型的规则进行编码。
我们来看一个简单的例子,它来自我们的[solidity_faucet_example]。在+Faucet.sol+中,我们为取款定义了一个函数:
function withdraw(uint withdraw_amount) public {
withdraw函数的_prototype_被定义为包含函数名称的字符串,随后是括号中括起来的每个参数的数据类型,并用单个逗号分隔。函数名称是+withdraw+,它只有一个参数是uint(它是uint256的别名)。所以+withdraw+的原型将是:
withdraw(uint256)
我们来计算这个字符串的Keccak256哈希值(我们可以使用truffle控制台或任何JavaScript web3控制台来做到这一点):
web3.sha3("withdraw(uint256)");
'0x2e1a7d4d13322e7b96f9a57413e1525c250fb7a9021cf91d1540d5b69f16a49f'
散列的前4个字节是 0x2e1a7d4d。这是我们的“函数选择器”的值,它会告诉EVM我们想调用哪个函数。
接下来,让我们计算一个值作为参数 withdraw_amount 传递。我们要取款0.01 ether。我们将它编码为一个十六进制序列化的大端序无符号256位整数,以wei为单位:
withdraw_amount = web3.toWei(0.01, "ether");
'10000000000000000'
withdraw_amount_hex = web3.toHex(withdraw_amount);
'0x2386f26fc10000'
现在,我们将函数选择器添加到这个参数上(填充为32字节):
2e1a7d4d000000000000000000000000000000000000000000000000002386f26fc10000
这就是我们的交易的 data,调用 withdraw 函数并请求0.01 ether作为 withdraw_amount。