简介
- 参考:https://substrate.dev/en/tutorials
- 参考:https://substrate.dev/docs/en/tutorials/add-contracts-pallet/
检查 Rust 版本
-
rustup toolchain list 查看版本。
-
rustc --version
- 如果版本不对,编译可能有问题。
修改运行时
-
在运行pallet类库中的 pallet -contracts-3.0.0 中定义了
-
pub mod weights
定义了自动生成 weights 的各种方法,我们需要引入它
首先需要天剑
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 的预编译情况
添加 RPC API 扩展
-
Substrate 提供了 pallet-contracts-rpc,下面需要将这个crate加到 node/Cargo.toml 里:
修改文件:
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
测试编译,并启动开发测试节点。
-
看到程序正常出块后打开
http://polkadot.js.org/apps/
访问 DEVELOPMENT->Local Node 然后点击转换的按钮。
-
可以看到多出合约,也就表示成功了。
结束
- 感谢阅读,接下来将测试合约。