捕获异常的唯一方法是对生成异常的 Promise 进行回调。
在解释的场景中,不contractA.callback()应该崩溃。您需要足够仔细地构建合约以避免回调失败。大多数情况下是可以做到的,因为您控制回调的输入和附加的气体量。如果回调失败,则类似于在异常处理代码中出现异常。
另请注意,您可以确保callback正确安排contractA.run(). 如果不是这种情况,例如您没有足够的 gas 附加到run,回调和其他承诺的调度将失败,并且整个run更改状态将回滚。但是一旦run完成,状态变化就会run被提交并且callback必须仔细处理。
我们在lockup合同中有几个地方允许回调失败:https ://github.com/near/core-contracts/blob/6fb13584d5c9eb1b372cfd80cd18f4a4ba8d15b6/lockup/src/owner_callbacks.rs#L7-L24
还有大多数回调不会失败的地方:https ://github.com/near/core-contracts/blob/6fb13584d5c9eb1b372cfd80cd18f4a4ba8d15b6/lockup/src/owner_callbacks.rs#L28-L61
指出在某些情况下合约不想依赖其他合约的稳定性,例如当流量为A --> B --> A --> B. 在这种情况下B,无法将回调附加到给定的资源A。对于这些场景,我们正在讨论添加一个特定构造的可能性,该构造是一个原子并且一旦它被删除就具有解析回调。我们称之为Safe:https ://github.com/nearprotocol/NEPs/pull/26
编辑
如果contractB.run失败并且我想更新状态contractA以回滚更改contractA.run怎么办?
在这种情况下contractA.callback()仍然被调用,但它具有PromiseResult::Failed它的依赖关系contractB.run。
因此callback()可以通过修改状态contractA来恢复更改。
例如,锁定合约实现的回调以处理从权益池合约中退出:https ://github.com/near/core-contracts/blob/6fb13584d5c9eb1b372cfd80cd18f4a4ba8d15b6/lockup/src/foundation_callbacks.rs#L143-L185
如果我们调整名称以匹配示例:
锁仓合约 ( contractA) 尝试run()从质押池 ( ) 中提取资金 ( contractB),但由于最近取消质押,资金可能仍被锁定,因此提取失败 (contractB.run()失败)。回调被称为 ( contractA.callback()) 并检查承诺 (of contractB.run) 的成功。由于提款失败,回调将状态恢复到原始状态(恢复状态)。
实际上,它稍微复杂一些,因为实际的序列是A.withdraw_all -> B.get_amount -> A.on_amount_for_withdraw -> B.withdraw(amount) -> A.on_withdraw