Substrate - 添加合约pallet

简介

  • 参考:https://substrate.dev/en/tutorials
  • 参考:https://substrate.dev/docs/en/tutorials/add-contracts-pallet/

检查 Rust 版本

  • rustup toolchain list 查看版本。


    image.png
  • rustc --version


    image.png
  • 如果版本不对,编译可能有问题。

修改运行时

  • 在运行pallet类库中的 pallet -contracts-3.0.0 中定义了


    image.png
  • pub mod weights 定义了自动生成 weights 的各种方法,我们需要引入它

    image.png

  • 首先需要天剑 WeightInfo trait 修改文件 runtime/src/lib.rs 搜索 use pallet_transaction_payment::CurrencyAdapter; 在这行代码下面加入:

use pallet_contracts::weights::WeightInfo;

/*** Add This Block ***/
// Contracts price units.
pub const MILLICENTS: Balance = 1_000_000_000;
pub const CENTS: Balance = 1_000 * MILLICENTS;
pub const DOLLARS: Balance = 100 * CENTS;

const fn deposit(items: u32, bytes: u32) -> Balance {
    items as Balance * 15 * CENTS + (bytes as Balance) * 6 * CENTS
}

/// We assume that ~10% of the block weight is consumed by `on_initalize` handlers.
/// This is used to limit the maximal weight of a single extrinsic.
const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10);

/*** End Added Block ***/

  • 搜索 impl pallet_timestamp::Config for Runtime 在这个下面添加如下代码:
/*** Add This Block ***/
parameter_types! {
    pub const TombstoneDeposit: Balance = deposit(
        1,
        sp_std::mem::size_of::>() as u32
    );
    pub const DepositPerContract: Balance = TombstoneDeposit::get();
    pub const DepositPerStorageByte: Balance = deposit(0, 1);
    pub const DepositPerStorageItem: Balance = deposit(1, 0);
    pub RentFraction: Perbill = Perbill::from_rational_approximation(1u32, 30 * DAYS);
    pub const SurchargeReward: Balance = 150 * MILLICENTS;
    pub const SignedClaimHandicap: u32 = 2;
    pub const MaxDepth: u32 = 32;
    pub const MaxValueSize: u32 = 16 * 1024;
    // The lazy deletion runs inside on_initialize.
    pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO *
        BlockWeights::get().max_block;
    // The weight needed for decoding the queue should be less or equal than a fifth
    // of the overall weight dedicated to the lazy deletion.
    pub DeletionQueueDepth: u32 = ((DeletionWeightLimit::get() / (
            ::WeightInfo::on_initialize_per_queue_item(1) -
            ::WeightInfo::on_initialize_per_queue_item(0)
        )) / 5) as u32;
    pub MaxCodeSize: u32 = 128 * 1024;
}

impl pallet_contracts::Config for Runtime {
    type Time = Timestamp;
    type Randomness = RandomnessCollectiveFlip;
    type Currency = Balances;
    type Event = Event;
    type RentPayment = ();
    type SignedClaimHandicap = SignedClaimHandicap;
    type TombstoneDeposit = TombstoneDeposit;
    type DepositPerContract = DepositPerContract;
    type DepositPerStorageByte = DepositPerStorageByte;
    type DepositPerStorageItem = DepositPerStorageItem;
    type RentFraction = RentFraction;
    type SurchargeReward = SurchargeReward;
    type MaxDepth = MaxDepth;
    type MaxValueSize = MaxValueSize;
    type WeightPrice = pallet_transaction_payment::Module;
    type WeightInfo = pallet_contracts::weights::SubstrateWeight;
    type ChainExtension = ();
    type DeletionQueueDepth = DeletionQueueDepth;
    type DeletionWeightLimit = DeletionWeightLimit;
    type MaxCodeSize = MaxCodeSize;
}
/*** End Added Block ***/
  • 为了能了解上面乱七八糟的内容可以读取 https://github.com/paritytech/substrate/blob/v3.0.0/frame/contracts/src/lib.rs 的源代码。

  • 修改 construct_runtime! 宏,然后添加如下代码:

construct_runtime!(
    pub enum Runtime where
        Block = Block,
        NodeBlock = opaque::Block,
        UncheckedExtrinsic = UncheckedExtrinsic
    {
        /* --snip-- */

        /*** Add This Line ***/
        Contracts: pallet_contracts::{Module, Call, Config, Storage, Event},
    }
);

更新节点信息

  • 在这个合约的实例中,我们将添加自定义的RPC的接入端点,并且配置创世配置。

向外暴露合约API

  • 修改 runtime/Cargo.toml
[dependencies]
#--snip--
pallet-contracts-rpc-runtime-api = { default-features = false, version = '3.0.0' 

[features]
default = ['std']
std = [
    #--snip--
    'pallet-contracts-rpc-runtime-api/std',
]

  • 修改 runtime/src/lib.rs
impl_runtime_apis! {
   /* --snip-- */

   /*** Add This Block ***/
    impl pallet_contracts_rpc_runtime_api::ContractsApi
    for Runtime
    {
        fn call(
            origin: AccountId,
            dest: AccountId,
            value: Balance,
            gas_limit: u64,
            input_data: Vec,
        ) -> pallet_contracts_primitives::ContractExecResult {
            Contracts::bare_call(origin, dest, value, gas_limit, input_data)
        }

        fn get_storage(
            address: AccountId,
            key: [u8; 32],
        ) -> pallet_contracts_primitives::GetStorageResult {
            Contracts::get_storage(address, key)
        }

        fn rent_projection(
            address: AccountId,
        ) -> pallet_contracts_primitives::RentProjectionResult {
            Contracts::rent_projection(address)
        }
    }
   /*** End Added Block ***/
}
  • 通过 cargo check -p node-template-runtime 命令检查一下 node-template-runtime 的预编译情况
    image.png

添加 RPC API 扩展

  • Substrate 提供了 pallet-contracts-rpc,下面需要将这个crate加到 node/Cargo.toml 里:


    image.png
  • 修改文件:node/Cargo.toml

[dependencies]
jsonrpc-core = '15.1.0'
structopt = '0.3.8'
#--snip--
# *** Add this 2 lines ***
pallet-contracts  = '3.0.0'
pallet-contracts-rpc  = '3.0.0'
  • 修改文件 node/src/rpc.rs
use node_template_runtime::{opaque::Block, AccountId, Balance, Index, BlockNumber}; // NOTE THIS IS AN ADJUSTMENT TO AN EXISTING LINE
use pallet_contracts_rpc::{Contracts, ContractsApi};
/// Instantiate all full RPC extensions.
pub fn create_full(
    deps: FullDeps,
) -> jsonrpc_core::IoHandler where
    /* --snip-- */
    C: Send + Sync + 'static,
    C::Api: substrate_frame_rpc_system::AccountNonceApi,
    /*** Add This Line ***/
    C::Api: pallet_contracts_rpc::ContractsRuntimeApi,
    /* --snip-- */
{
    /* --snip-- */
    io.extend_with(
        TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone()))
    );
    /*** Add This Block ***/
    // Contracts RPC API extension
    io.extend_with(
        ContractsApi::to_delegate(Contracts::new(client.clone()))
    );
    /*** End Added Block ***/
    io
}

修改创世区块信息

  • 修改文件 node/src/chain_spec.rs
// 在文件顶部添加:
use node_template_runtime::ContractsConfig;
/// Configure initial storage state for FRAME modules.
fn testnet_genesis(
    wasm_binary: &[u8],
    initial_authorities: Vec<(AuraId, GrandpaId)>,
    root_key: AccountId,
    endowed_accounts: Vec,
    enable_println: bool, // Update this line
) -> GenesisConfig {
    GenesisConfig {
        /* --snip-- */

        /*** Add This Block ***/
        pallet_contracts: Some(ContractsConfig {
            current_schedule: pallet_contracts::Schedule {
                    enable_println,
                    ..Default::default()
            },
        }),
        /*** End Added Block ***/
    }
}

测试节点

  • 首先通过命令 cargo run -- --dev --tmp 测试编译,并启动开发测试节点。

    image.png

  • 看到程序正常出块后打开 http://polkadot.js.org/apps/ 访问 DEVELOPMENT->Local Node 然后点击转换的按钮。

    image.png

  • 可以看到多出合约,也就表示成功了。


    image.png

结束

  • 感谢阅读,接下来将测试合约。

你可能感兴趣的:(Substrate - 添加合约pallet)