科普 | 为什么使用提款(Withdrawal)模式?
《建立以太坊支付通道》这篇文章引发了这样一个问题:为什么关闭一个支付通道要将资金增加到一个账户,而不是简单地将资金返还给通道参与者。这种机制被称为提款模式,这篇文章将解释其必要性。
当一笔以太坊交易试图将资金释放到不受交易发起人控制的地址时,问题就出现了。一个非常简化的合约例子如下所示:
contract BadSplitter {
uint256 funds;
address sender;
address recipient;
// Deposit some funds in to the contract
function deposit(address other) payable {
funds = msg.value;
sender = msg.sender;
recipient = other;
}
// Split an amount of funds between the sender and the recipient
function split() {
// Can only be called by the recipient
require(msg.sender == recipient);
// Split the funds
sender.transfer(funds / 2);
recipient.transfer(funds / 2);
}
(请注意,本智能合约纯粹是为了说明目的,完全不具有任何实用价值。)
本合约的运作方式如下:
发送方发起一个
deposit()
事务,并附上接收方的地址。接收方发起一个
split()
事务,该交易将一半的存款发送给接收方,另一半发送回发送方。
或如图所示:
没有代码循环或限制条件,所以控制流程很容易遵循。那会出现什么问题呢?
问题在于,账户和合约都是交易的有效参与者,而作为交易的一部分,当这些合约收到资金时,合约会按照代码来执行。
当合约收到资金时,它会在合约上调用一个特殊的函数,称为回退(Fallback)函数。这允许合约控制调用它的交易的控制流程。
一个纯粹的恶意合约如下所示:
contract BadSender {
// Forward funds to the splitter contract
function forward(address other) payable {
// This is the address of the splitter contract
address splitterContract = 0xAe3aE77F5ab2490C46958D0b05f766871c17cA5e;
BadSplitter splitter = BadSplitter(splitterContract);
splitter.deposit.gas(200000).value(msg.value)(other);
}
// Purely malevolent fallback
function () {
revert();
}
}
本合约的运作方式如下:
发送方发起一个
forward()
事务,并附上接收方的地址。这将调用前面描述的恶意拆分合约(BadSplitter Contract)。当接收方试图在恶意拆分合约中调用拆分
split()
时,他们发现他们的交易失败了。这是因为恶意拆分引起sender.transfer()
调用恶意拆分中的回退函数,该函数立即失效,并导致整个交易失效。
或如图所示:
重点是要明白:回滚(Reverting)交易会取消原交易采取的所有行动,所以回滚后以太坊的状态就好像从未发生过交易一样。如若没有这个 reverse()
方程,在发送者之前写一个简单的合约,向接受者发送资金就可以避免提款失败。
正如上面所提到的,这是一种纯粹的恶意合约,因为它会无条件地禁止接收者地址获得其资金。然而,鉴于智能合约是一个程序,一个更高级的恶意发送者(BadSender)可以根据时间、某个帐户的余额、一个内部标志等来允许或拒绝交易。恶意的可能性是无止境的,并且发送者还可以要求接收者支付赎金。
在支付通道的情境中,这会有负面的影响,因为当接受者试图关闭通道时,一个恶意发送者可能会回滚交易,不让接受者获得应得的资金。一旦通道在到期时间关闭,发送方可能会终止该通道、接收所有已存的资金,且永久地剥夺接收方所应得的资金。
解决这个问题的办法是使用提款模式。通过跟踪合约内部的余额,并迫使每个用户撤回自己的资金,从而在交易中的另一方可能是恶意合约的事实变得无关紧要。关于提款模式的更多细节可以在 solidity 官方文件中找到。
原文链接: https://medium.com/@jgm.orinoco/why-use-the-withdrawal-pattern-d5255921ca2a
作者: Jim McDonald
翻译&校对: Waterzeong & Elisa
本文由作者授权 EthFans 翻译及再出版。
你可能还会喜欢:
干货 | 代币支付的以太坊智能服务
引介 | 域名销售:一个链上二级ENS市场
教程 | 在区块链上建立可更新的智慧合约(一)<https://ethfans.org/posts/how-to-build-updateable-smart-contract-part-1>