Polkadot 在 2.0 里面引入了新的 PolkaVM 来支持智能合约的运行,并且使用 Revive Pallet 兼容 EVM。通过 Resolc 的编译,solidity 代码可以在 PolkaVM 上更加高效的运行。
/// The Sha256 precompile.
pub struct Sha256;
impl<T: Config> Precompile<T> for Sha256 {
fn execute(gas_meter: &mut GasMeter<T>, input: &[u8]) -> Result<ExecReturnValue, &'static str> {
gas_meter.charge(RuntimeCosts::HashSha256(input.len() as u32))?;
let data = sp_io::hashing::sha2_256(input).to_vec();
Ok(ExecReturnValue { data, flags: ReturnFlags::empty() })
}
}
对这些 precompile 的调用入口在 pure precompile.rs (🔗 https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/src/pure_precompiles.rs#L59) 源文件里面,execute 方法通过合约地址的最后一个字节来找到需要调用的合约。可以看到 Sha256 的编号是 2,而 ECRecover 的是 1.
为什么只比较最后一个字节,因为我们把前 19 个字节都是 0 的分配给了 precompile 地址空间。
pub fn is_precompile(address: &H160) -> bool {
let bytes = address.as_bytes();
bytes.starts_with(&[0u8; 19]) && bytes[19] != 0
}
在运行到合约执行的时候,runtime 总是先通过地址来判断是否为 precompile 的合约。这个判断逻辑在 call (🔗: https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/src/exec.rs#L1485) 和 delegate call (🔗:https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/src/exec.rs#L1564) 最开始进行,如果是 precompile 合约,直接转到 Runtime 里面运行。不同版本的代码行数可以有区别,只需要搜索 is_precompile 就可以。
在理解了 precompile 以及他们的地址,我们就可以尝试着来调用他们。我们还是以 sha256 为例子,我们写一个简单的 solidity 合约,代码如下:合约非常简单,首先定义一个地址,然后通过 call 这个函数来调用 sha256 方法,这里可以输入一个 bytes 作为 input,并把它的结果放到链上存贮 result 里面。
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.2 <0.9.0;
contract Storage {
event CallPrecompile(bytes);
bytes result;
function callH256(bytes calldata input) public {
// address of precompile h256
address precompile = address(0x02);
// result
bool success;
bytes memory resultInMemory;
// just call it without selector
(success, resultInMemory) = precompile.call{value: 0}(input);
// emit the result
if (success) {
emit CallPrecompile(resultInMemory);
}
// put result in storage
result = resultInMemory;
}
}
我们打开 polkaVM 的 remix,在浏览器中输入 https://remix.polkadot.io
把这个合约加到一个源文件中,并编译和部署。得到地址后,调用 callH256 函数,测试数据可以从这个文件(🔗 https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/src/pure_precompiles/testdata/2-sha256.json)得到, 里面包含输入和输出的正确结果。
运行结果截图如下:
本文简单的介绍了 revive 里面 precompile 具体实现和使用方法,大家可以关注 precompile 的变化,可能会包含你所需要的功能,这样就可以直接使用了,不需要自己在去实现。
如果你是在自己的链上引入了 revive,也可以根据需要自己添加 precompile 合约,把需要的 runtime 里面的功能暴露给智能合约来调用,或者将常用的算法,函数放在 precompile,提高运行效率,减少合约大小。
免责声明:由 PaperMoon 提供并包含在本文中的材料仅用于学习目的。它们不构成财务或投资建议,也不应被解读为任何商业决策的指导。我们建议读者在做出任何投资或商业相关的决定之前,进行独立研究并咨询专业人士。PaperMoon 对根据本文内容采取的任何行动不承担任何责任。
About Us
关于我们
Twitter: https://twitter.com/OneBlock_ Medium: https://medium.com/@OneBlockplus Telegram: https://t.me/oneblock_dev Discord: https://discord.gg/fE8deY4UbP Bilibili: https://space.bilibili.com/1650224419 YouTube: https://www.youtube.com/channel/UCWo2r3wA6brw3ztr-JmzyXA
【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。