Skip to content

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.jsWeb3.jsWeb3.py)与Registry Precompile交互。

以下操作将以Moonbase Alpha为例。 要在Moonbeam或Moonriver网络上测试本指南中的示例,您可以从受支持的网络端点提供商之一获取您自己的端点和API密钥。

使用Remix与Precompile Registry交互

要快速开始使用RemixPrecompile Registry合约已从GitHub加载。您也可以在Remix创建一个新文件并手动在PrecompileRegistry.sol合约中粘贴内容。

Add the Precompile Registry Interface to Remix

然后,您可以执行以下步骤进行编译、部署并与Precompile Registry交互:

  1. Compile标签下,点击Compile PrecompileRegistry.sol开始编译合约。成功编译合约后将会在左侧出现绿色完成标记

    Compile the Precompile Registry contract

  2. Deploy and run transactions标签下,您可以使用地址加载Precompile Registry:

    1. 确保在ENVIRONMENT的下拉菜单中选择Injected Provider - Metamask,并已将MetaMask连接至Moonbase Alpha

    2. 确保在CONTRACT下拉菜单中选择PrecompileRegistry。因为这是一个已经预编译的合约,因此无需部署,但是您需要在At Address字段中提供预编译的地址

    3. 为Moonbase Alpha提供Precompile Registry的地址:0x0000000000000000000000000000000000000815并点击At Address

    4. Precompile Registry将在Deployed Contracts列表中出现

    Access the Precompile Registry contract

  3. 您可以与任何预编译的函数交互。在Deployed Contracts标签下方,展开Precompile Registry查看函数列表。例如,您可以使用isPrecompile函数查看该地址是否是预编译

    Interact with the Precompile Registry contract

使用以太坊库与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交互。通常情况下,您需要执行以下步骤:

  1. 创建一个提供商

  2. 创建一个Precompile Registry的合约实例

  3. 与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()
Last update: January 25, 2024
| Created: July 12, 2023