rust - Staking-pool 核心合约 - ext_contract 宏和回调
问题描述
在函数中,当它是调用合约的一部分时
internal_restake
,为什么我们必须像外部交叉合约调用一样访问该函数?on_stake_action
难道我们就不能这样做.then(self.on_stake_action())
吗?我假设这与它是来自stake()
承诺调用的回调有关。在什么情况下你会为合约本身做一个接口
ext_self
?简而言之,#[ext_contract()] 宏做了什么?
-------- Staking Pool Contract Code 下面 -------- lib.rs 第 155~162 行
/// Interface for the contract itself.
#[ext_contract(ext_self)]
pub trait SelfContract {
/// A callback to check the result of the staking action.
fn on_stake_action(&mut self);
}
pub fn on_stake_action(&mut self) {
assert_eq!(
env::current_account_id(),
env::predecessor_account_id(),
"Can be called only as a callback"
);
assert_eq!(
env::promise_results_count(),
1,
"Contract expected a result on the callback"
);
let stake_action_succeeded = match env::promise_result(0) {
PromiseResult::Successful(_) => true,
_ => false,
};
// If the stake action failed and the current locked amount is positive, then the contract
// has to unstake.
if !stake_action_succeeded && env::account_locked_balance() > 0 {
Promise::new(env::current_account_id()).stake(0, self.stake_public_key.clone());
}
}
/// Restakes the current `total_staked_balance` again.
pub(crate) fn internal_restake(&mut self) {
if self.paused {
return;
}
// Stakes with the staking public key. If the public key is invalid the entire function
// call will be rolled back.
Promise::new(env::current_account_id())
.stake(self.total_staked_balance, self.stake_public_key.clone())
.then(ext_self::on_stake_action(
&env::current_account_id(),
NO_DEPOSIT,
ON_STAKE_ACTION_GAS,
));
}
解决方案
合约的“外部”接口的原因是对该方法的调用是外部的,因为它是作为承诺操作的一部分“调用”的。
/// Interface for the contract itself.
#[ext_contract(ext_self)]
pub trait SelfContract {
/// A callback to check the result of the staking action.
fn on_stake_action(&mut self);
}
首先,在 rust 程序宏中,输入和输出中的标记流 ( pub
, trait
, SelfContract
, ...)。在这种情况下,输出不是一个特征,而是一个模块](https://doc.rust-lang.org/reference/items/modules.html)命名ext_self
。然后将一个函数on_stake_action
添加到模块中,并使用删除 self 参数和添加三个新参数进行修改,并返回一个Promise
.
Promise::new(env::current_account_id())
.stake(self.total_staked_balance, self.stake_public_key.clone())
.then(ext_self::on_stake_action(
&env::current_account_id(),
NO_DEPOSIT,
ON_STAKE_ACTION_GAS,
));
注意ext_self
,模块::
是访问的路径分离器on_stake_action
,是&env::current_account_id()
接收器,NO_DEPOSIT
是附加的存款,ON_STAKE_ACTION_GAS
是承诺调用的气体。此外,生成了用于实现该功能的代码;它对函数的参数进行编码(在这种情况下没有任何参数)并创建一个调用方法的承诺on_stake_action
。
最初声明这是一个特征的原因是它不需要实现,并且具有良好 rust 支持的 IDE 已经扩展了这个宏,允许您将其ext_self
用作模块,即使您看不到它是什么.
尽管该ext_contract
宏将对同一合约的调用与其他合约相同,但您提出了一个很好的观点。所以也许一个新的有用功能是创建一个已经使用的新宏env::current_account_id()
。
推荐阅读
- react-native - 在 IOS 中同时实现 react-native-appodeal 和 react-native-fbsdk-next 时发生冲突
- linux - 如何使用 cgroup v2 从容器中获取 docker 容器 ID
- json - 我正在尝试检索数据并在列表视图中显示,但它显示错误
- php - How to preg_match country phone number code
- java - 检查上传的文件是否在 Flux 中不为空
- android - 如何在firebase phone-auth (OTP) android中禁用/删除reCaptcha?
- ajax - 使用 ajax 使用 javascript 变量更新数据库
- android-studio - 没有方法签名:build
- python-3.x - 在 docker 中安装 python 3.5 和基本镜像 centos7
- python - 如何通过python中不同大小的其他数据框中的列中的值过滤数据框?