Moonbeam上的Precompile Registry¶
概览¶
Precompile Registry作为Moonbeam上可用预编译的单一数据源。Precompile Registry可用于确定地址是否对应于预编译,以及是否处于活跃状态或已启用。当Substrate和Polkadot生态系统中存在上游变化导致预编译发生向后不兼容的变化时,Precompile Registry的作用将非常有效。开发者可以设计退出策略,以确保其dApp在这些场景中能够正常恢复。
Precompile Registry还有另外一个作用,允许任何用户为预编译设置“虚拟代码”(0x60006000fd
),这使预编译可以从Solidity调用。此功能必不可少,因为Moonbeam上的预编译在默认情况下是没有字节码的。“虚拟代码”可以绕过Solidity中的检查,以确保合约字节码的存在以及不是空白的。
Registry Precompile位于以下地址:
0x0000000000000000000000000000000000000815
0x0000000000000000000000000000000000000815
0x0000000000000000000000000000000000000815
注意事项
在Moonbeam使用预编译合约时,可能会出现一些意想不到的后果。 请参阅安全注意事项 页面了解更多信息。
Registry Precompile Solidity接口¶
PrecompileRegistry.sol
是一个Solidity接口,允许开发者与预编译函数交互。
PrecompileRegistry.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.3;
/// @dev The Precompile Registry contract's address.
address constant PRECOMPILE_REGISTRY_ADDRESS = 0x0000000000000000000000000000000000000815;
/// @dev The Precompile Registry contract's instance.
PrecompileRegistry constant PRECOMPILE_REGISTRY_CONTRACT = PrecompileRegistry(PRECOMPILE_REGISTRY_ADDRESS);
/// @author The Moonbeam Team
/// @title Precompile Registry
/// @dev Interface to the set of available precompiles.
interface PrecompileRegistry {
/// @dev Query if the given address is a precompile. Note that deactivated precompiles
/// are still considered precompiles and will return `true`.
/// @param a: Address to query
/// @return output Is this address a precompile?
/// @custom:selector 446b450e
function isPrecompile(address a) external view returns (bool);
/// @dev Query if the given address is an active precompile. Will return false if the
/// address is not a precompile or if this precompile is deactivated.
/// @param a: Address to query
/// @return output Is this address an active precompile?
/// @custom:selector 6f5e23cf
function isActivePrecompile(address a) external view returns (bool);
/// @dev Update the account code of a precompile address.
/// As precompiles are implemented inside the Runtime, they don't have a bytecode, and
/// their account code is empty by default. However in Solidity calling a function of a
/// contract often automatically adds a check that the contract bytecode is non-empty.
/// For that reason a dummy code (0x60006000fd) can be inserted at the precompile address
/// to pass that check. This function allows any user to insert that code to precompile address
/// if they need it.
/// @param a: Address of the precompile.
/// @custom:selector 48ceb1b4
function updateAccountCode(address a) external;
}
- isPrecompile(address a) - 返回bool指示给定地址是否为预编译。对于活跃或已启用的预编译返回
true
- isActivePrecompile(address a) - 返回bool指示给定地址是否为预编译。如果预编译已被弃用则返回
false
- updateAccountCode(address a) - 使用给定预编译地址的虚拟代码(
0x60006000fd
)更新给定预编译的字节码。 默认情况下,预编译没有与之关联的字节码。此函数可用于添加虚拟字节码以绕过Solidity中的检查,以在调用合约函数之前检查合约的字节码是否不是空白
与Precompile Registry Solidity交互¶
以下部分将概述如何从Remix和以太坊库(例如Ethers.js、Web3.js和Web3.py)与Registry Precompile交互。
以下操作将以Moonbase Alpha为例。 要在Moonbeam或Moonriver网络上测试本指南中的示例,您可以从受支持的网络端点提供商之一获取您自己的端点和API密钥。
使用Remix与Precompile Registry交互¶
要快速开始使用Remix,Precompile Registry合约已从GitHub加载。您也可以在Remix创建一个新文件并手动在PrecompileRegistry.sol
合约中粘贴内容。
然后,您可以执行以下步骤进行编译、部署并与Precompile Registry交互:
-
在Compile标签下,点击Compile PrecompileRegistry.sol开始编译合约。成功编译合约后将会在左侧出现绿色完成标记
-
在Deploy and run transactions标签下,您可以使用地址加载Precompile Registry:
-
确保在ENVIRONMENT的下拉菜单中选择Injected Provider - Metamask,并已将MetaMask连接至Moonbase Alpha
-
确保在CONTRACT下拉菜单中选择PrecompileRegistry。因为这是一个已经预编译的合约,因此无需部署,但是您需要在At Address字段中提供预编译的地址
-
为Moonbase Alpha提供Precompile Registry的地址:
0x0000000000000000000000000000000000000815
并点击At Address -
Precompile Registry将在Deployed Contracts列表中出现
-
-
您可以与任何预编译的函数交互。在Deployed Contracts标签下方,展开Precompile Registry查看函数列表。例如,您可以使用isPrecompile函数查看该地址是否是预编译
使用以太坊库与Precompile Registry交互¶
要使用以太坊库与Precompile Registry的Solidity接口交互,您将需要Precompile Registry的ABI。
Precompile Registry ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "a",
"type": "address"
}
],
"name": "isActivePrecompile",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "a",
"type": "address"
}
],
"name": "isPrecompile",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "a",
"type": "address"
}
],
"name": "updateAccountCode",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
有了ABI之后,您可以根据您的选择使用以太坊库与Registry交互。通常情况下,您需要执行以下步骤:
-
创建一个提供商
-
创建一个Precompile Registry的合约实例
-
与Precompile Registry的函数交互
请记住
以下代码片段仅用于演示目的。请勿将您的私钥存储在JavaScript或Python文件中。
import { ethers } from 'ethers'; // Import Ethers library
import ABI from './precompileRegistryABI.js'; // Import Precompile Registry ABI
const privateKey = 'INSERT_PRIVATE_KEY';
// Create Ethers provider and signer
const provider = new ethers.JsonRpcProvider(
'https://rpc.api.moonbase.moonbeam.network'
);
const signer = new ethers.Wallet(privateKey, provider);
// Create interface for the Precompile Registry
const precompileRegistry = new ethers.Contract(
'0x0000000000000000000000000000000000000815',
ABI,
signer
);
// Interact with the Precompile Registry
const isActivePrecompile = async () => {
const proxyPrecompile = '0x000000000000000000000000000000000000080b';
// Check if the Proxy Precompile is a precompile
const isPrecompile = await precompileRegistry.isPrecompile(proxyPrecompile);
// Should return 'Address is a precompile: true'
console.log(`Address is a precompile: ${isPrecompile}`);
// Check if the Proxy Precompile is an active precompile
const isActivePrecompile = await precompileRegistry.isActivePrecompile(
proxyPrecompile
);
// Should return 'Address is an active precompile: true'
console.log(`Address is an active precompile: ${isActivePrecompile}`);
};
isActivePrecompile();
import { Web3 } from 'web3';
import ABI from './precompileRegistryABI.js'; // Import Precompile Registry ABI
const privateKey = 'INSERT_PRIVATE_KEY';
// Create provider
const web3 = new Web3('https://rpc.api.moonbase.moonbeam.network');
// Create interface for the Precompile Registry
const precompileRegistry = new web3.eth.Contract(
ABI,
'0x0000000000000000000000000000000000000815',
{ from: web3.eth.accounts.privateKeyToAccount(privateKey).address }
);
// Interact with the Precompile Registry
const isActivePrecompile = async () => {
const proxyPrecompile = '0x000000000000000000000000000000000000080b';
// Check if the Proxy Precompile is a precompile
const isPrecompile = await precompileRegistry.methods.isPrecompile(
proxyPrecompile
).call();
// Should return 'Address is a precompile: true'
console.log(`Address is a precompile: ${isPrecompile}`);
// Check if the Proxy Precompile is an active precompile
const isActivePrecompile =
await precompileRegistry.methods.isActivePrecompile(proxyPrecompile).call();
// Should return 'Address is an active precompile: true'
console.log(`Address is a precompile: ${isActivePrecompile}`);
};
isActivePrecompile();
from web3 import Web3
abi = "INSERT_PRECOMPILE_REGISTRY_ABI" # Paste or import the Precompile Registry ABI
private_key = "INSERT_PRIVATE_KEY"
# Create provider
web3 = Web3(Web3.HTTPProvider("https://rpc.api.moonbase.moonbeam.network"))
# Create interface for the Precompile Registry
precompile_registry = web3.eth.contract(
address="0x0000000000000000000000000000000000000815", abi=abi
)
# Interact with the Precompile Registry
def is_active_precompile():
proxy_precompile = "0x000000000000000000000000000000000000080b"
# Check if the Proxy Precompile is a precompile
is_precompile = precompile_registry.functions.isPrecompile(proxy_precompile).call()
# Should return 'Address is a precompile: true'
print("Address is a precompile: ", is_precompile)
# Check if the Proxy Precompile is an active precompile
is_active_precompile = precompile_registry.functions.isActivePrecompile(
proxy_precompile
).call()
# Should return 'Address is an active precompile: true'
print("Address is an active precompile: ", is_active_precompile)
is_active_precompile()
| Created: July 12, 2023