mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 11:41:02 +00:00
One node two runtimes (#191)
* One node two runtimes This enables the rococo-collator to run the normal and the contracts runtime. * Fix tests
This commit is contained in:
Generated
+16
@@ -976,6 +976,7 @@ dependencies = [
|
|||||||
"parachain-info",
|
"parachain-info",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"polkadot-parachain",
|
"polkadot-parachain",
|
||||||
|
"rococo-parachain-primitives",
|
||||||
"serde",
|
"serde",
|
||||||
"sp-api",
|
"sp-api",
|
||||||
"sp-block-builder",
|
"sp-block-builder",
|
||||||
@@ -1213,6 +1214,7 @@ dependencies = [
|
|||||||
"parachain-info",
|
"parachain-info",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"polkadot-parachain",
|
"polkadot-parachain",
|
||||||
|
"rococo-parachain-primitives",
|
||||||
"serde",
|
"serde",
|
||||||
"sp-api",
|
"sp-api",
|
||||||
"sp-block-builder",
|
"sp-block-builder",
|
||||||
@@ -5831,6 +5833,7 @@ dependencies = [
|
|||||||
"polkadot-test-runtime-client",
|
"polkadot-test-runtime-client",
|
||||||
"polkadot-test-service",
|
"polkadot-test-service",
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
|
"rococo-parachain-primitives",
|
||||||
"sc-basic-authorship",
|
"sc-basic-authorship",
|
||||||
"sc-chain-spec",
|
"sc-chain-spec",
|
||||||
"sc-cli",
|
"sc-cli",
|
||||||
@@ -5840,15 +5843,20 @@ dependencies = [
|
|||||||
"sc-finality-grandpa",
|
"sc-finality-grandpa",
|
||||||
"sc-informant",
|
"sc-informant",
|
||||||
"sc-network",
|
"sc-network",
|
||||||
|
"sc-rpc",
|
||||||
"sc-service",
|
"sc-service",
|
||||||
"sc-transaction-pool",
|
"sc-transaction-pool",
|
||||||
"serde",
|
"serde",
|
||||||
"sp-api",
|
"sp-api",
|
||||||
|
"sp-block-builder",
|
||||||
|
"sp-blockchain",
|
||||||
"sp-consensus",
|
"sp-consensus",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-inherents",
|
"sp-inherents",
|
||||||
"sp-io",
|
"sp-io",
|
||||||
|
"sp-offchain",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
|
"sp-session",
|
||||||
"sp-timestamp",
|
"sp-timestamp",
|
||||||
"sp-transaction-pool",
|
"sp-transaction-pool",
|
||||||
"sp-trie",
|
"sp-trie",
|
||||||
@@ -5860,6 +5868,14 @@ dependencies = [
|
|||||||
"trie-root 0.15.2",
|
"trie-root 0.15.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rococo-parachain-primitives"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"sp-core",
|
||||||
|
"sp-runtime",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rococo-runtime"
|
name = "rococo-runtime"
|
||||||
version = "0.8.22"
|
version = "0.8.22"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ members = [
|
|||||||
"rococo-parachains/contracts-runtime",
|
"rococo-parachains/contracts-runtime",
|
||||||
"rococo-parachains/pallets/parachain-info",
|
"rococo-parachains/pallets/parachain-info",
|
||||||
"rococo-parachains/pallets/token-dealer",
|
"rococo-parachains/pallets/token-dealer",
|
||||||
|
"rococo-parachains/primitives",
|
||||||
"rococo-parachains/runtime",
|
"rococo-parachains/runtime",
|
||||||
"runtime",
|
"runtime",
|
||||||
"service",
|
"service",
|
||||||
|
|||||||
@@ -518,8 +518,7 @@ where
|
|||||||
Box::new(self.polkadot_network.clone()),
|
Box::new(self.polkadot_network.clone()),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
let follow =
|
let follow = match cumulus_consensus::follow_polkadot(
|
||||||
match cumulus_consensus::follow_polkadot(
|
|
||||||
self.para_id,
|
self.para_id,
|
||||||
self.client,
|
self.client,
|
||||||
polkadot_client,
|
polkadot_client,
|
||||||
|
|||||||
@@ -23,7 +23,10 @@ mod tests;
|
|||||||
|
|
||||||
use sp_api::ProvideRuntimeApi;
|
use sp_api::ProvideRuntimeApi;
|
||||||
use sp_blockchain::{Error as ClientError, HeaderBackend};
|
use sp_blockchain::{Error as ClientError, HeaderBackend};
|
||||||
use sp_consensus::{block_validation::{BlockAnnounceValidator, Validation}, SyncOracle};
|
use sp_consensus::{
|
||||||
|
block_validation::{BlockAnnounceValidator, Validation},
|
||||||
|
SyncOracle,
|
||||||
|
};
|
||||||
use sp_core::traits::SpawnNamed;
|
use sp_core::traits::SpawnNamed;
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
generic::BlockId,
|
generic::BlockId,
|
||||||
|
|||||||
@@ -17,9 +17,9 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use cumulus_test_runtime::{Block, Header};
|
use cumulus_test_runtime::{Block, Header};
|
||||||
use polkadot_primitives::v0::{
|
use polkadot_primitives::v0::{
|
||||||
AbridgedCandidateReceipt, Chain, CollatorId, DutyRoster, GlobalValidationData,
|
AbridgedCandidateReceipt, Block as PBlock, Chain, CollatorId, DutyRoster, GlobalValidationData,
|
||||||
Id as ParaId, LocalValidationData, ParachainHost, Retriable, SigningContext,
|
Hash as PHash, Header as PHeader, Id as ParaId, LocalValidationData, ParachainHost, Retriable,
|
||||||
ValidationCode, ValidatorId, Block as PBlock, Hash as PHash, Header as PHeader,
|
SigningContext, ValidationCode, ValidatorId,
|
||||||
};
|
};
|
||||||
use polkadot_test_runtime_client::{
|
use polkadot_test_runtime_client::{
|
||||||
DefaultTestClientBuilderExt, TestClient, TestClientBuilder, TestClientBuilderExt,
|
DefaultTestClientBuilderExt, TestClient, TestClientBuilder, TestClientBuilderExt,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ hex-literal = "0.2.1"
|
|||||||
# Parachain dependencies
|
# Parachain dependencies
|
||||||
parachain-runtime = { package = "cumulus-test-parachain-runtime", path = "runtime" }
|
parachain-runtime = { package = "cumulus-test-parachain-runtime", path = "runtime" }
|
||||||
parachain-contracts-runtime = { package = "cumulus-contracts-parachain-runtime", path = "contracts-runtime" }
|
parachain-contracts-runtime = { package = "cumulus-contracts-parachain-runtime", path = "contracts-runtime" }
|
||||||
|
rococo-parachain-primitives = { path = "primitives" }
|
||||||
|
|
||||||
# Substrate dependencies
|
# Substrate dependencies
|
||||||
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "rococo-branch" }
|
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "rococo-branch" }
|
||||||
@@ -32,6 +33,7 @@ sp-io = { git = "https://github.com/paritytech/substrate", branch = "rococo-bran
|
|||||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
sp-core = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
||||||
sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
||||||
sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
||||||
|
sp-session = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
||||||
sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
||||||
sc-cli = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
sc-cli = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
||||||
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
||||||
@@ -42,11 +44,15 @@ sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch
|
|||||||
sc-network = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
sc-network = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
||||||
sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch", version = "0.8.0-rc5" }
|
sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch", version = "0.8.0-rc5" }
|
||||||
sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
||||||
|
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
||||||
|
sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
||||||
sp-trie = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
sp-trie = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
||||||
sp-api = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
sp-api = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
||||||
sc-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
sc-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
||||||
sc-informant = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
sc-informant = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
||||||
sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
||||||
|
sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
||||||
|
sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" }
|
||||||
|
|
||||||
# RPC related dependencies
|
# RPC related dependencies
|
||||||
cumulus-pallet-contracts-rpc = { path = "./pallets/contracts/rpc" }
|
cumulus-pallet-contracts-rpc = { path = "./pallets/contracts/rpc" }
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ codec = { package = "parity-scale-codec", version = "1.3.0", default-features =
|
|||||||
|
|
||||||
cumulus-token-dealer = { path = "../pallets/token-dealer", default-features = false}
|
cumulus-token-dealer = { path = "../pallets/token-dealer", default-features = false}
|
||||||
parachain-info = { path = "../pallets/parachain-info", default-features = false}
|
parachain-info = { path = "../pallets/parachain-info", default-features = false}
|
||||||
|
rococo-parachain-primitives = { path = "../primitives", default-features = false}
|
||||||
|
|
||||||
# Substrate dependencies
|
# Substrate dependencies
|
||||||
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "rococo-branch" }
|
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "rococo-branch" }
|
||||||
@@ -79,6 +80,7 @@ std = [
|
|||||||
"pallet-sudo/std",
|
"pallet-sudo/std",
|
||||||
"pallet-transaction-payment/std",
|
"pallet-transaction-payment/std",
|
||||||
"parachain-info/std",
|
"parachain-info/std",
|
||||||
|
"rococo-parachain-primitives/std",
|
||||||
"cumulus-runtime/std",
|
"cumulus-runtime/std",
|
||||||
"cumulus-parachain-upgrade/std",
|
"cumulus-parachain-upgrade/std",
|
||||||
"cumulus-message-broker/std",
|
"cumulus-message-broker/std",
|
||||||
|
|||||||
@@ -23,13 +23,14 @@
|
|||||||
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
||||||
|
|
||||||
use cumulus_pallet_contracts_rpc_runtime_api::ContractExecResult;
|
use cumulus_pallet_contracts_rpc_runtime_api::ContractExecResult;
|
||||||
|
use rococo_parachain_primitives::*;
|
||||||
use sp_api::impl_runtime_apis;
|
use sp_api::impl_runtime_apis;
|
||||||
use sp_core::OpaqueMetadata;
|
use sp_core::OpaqueMetadata;
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
create_runtime_str, generic, impl_opaque_keys,
|
create_runtime_str, generic, impl_opaque_keys,
|
||||||
traits::{BlakeTwo256, Block as BlockT, IdentifyAccount, IdentityLookup, Saturating, Verify},
|
traits::{BlakeTwo256, Block as BlockT, IdentityLookup, Saturating},
|
||||||
transaction_validity::{TransactionSource, TransactionValidity},
|
transaction_validity::{TransactionSource, TransactionValidity},
|
||||||
ApplyExtrinsicResult, MultiSignature,
|
ApplyExtrinsicResult,
|
||||||
};
|
};
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@@ -49,61 +50,18 @@ pub use pallet_timestamp::Call as TimestampCall;
|
|||||||
pub use sp_runtime::BuildStorage;
|
pub use sp_runtime::BuildStorage;
|
||||||
pub use sp_runtime::{Perbill, Permill};
|
pub use sp_runtime::{Perbill, Permill};
|
||||||
|
|
||||||
/// An index to a block.
|
|
||||||
pub type BlockNumber = u32;
|
|
||||||
|
|
||||||
/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
|
|
||||||
pub type Signature = MultiSignature;
|
|
||||||
|
|
||||||
/// Some way of identifying an account on the chain. We intentionally make it equivalent
|
|
||||||
/// to the public key of our transaction signing scheme.
|
|
||||||
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
|
|
||||||
|
|
||||||
/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
|
|
||||||
/// never know...
|
|
||||||
pub type AccountIndex = u32;
|
|
||||||
|
|
||||||
/// Balance of an account.
|
|
||||||
pub type Balance = u128;
|
|
||||||
|
|
||||||
/// Index of a transaction in the chain.
|
|
||||||
pub type Index = u32;
|
|
||||||
|
|
||||||
/// A hash of some data used by the chain.
|
|
||||||
pub type Hash = sp_core::H256;
|
|
||||||
|
|
||||||
/// Digest item type.
|
|
||||||
pub type DigestItem = generic::DigestItem<Hash>;
|
|
||||||
|
|
||||||
/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
|
|
||||||
/// the specifics of the runtime. They can then be made to be agnostic over specific formats
|
|
||||||
/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
|
|
||||||
/// to even the core datastructures.
|
|
||||||
pub mod opaque {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
|
|
||||||
|
|
||||||
/// Opaque block header type.
|
|
||||||
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
|
|
||||||
/// Opaque block type.
|
|
||||||
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
|
||||||
/// Opaque block identifier type.
|
|
||||||
pub type BlockId = generic::BlockId<Block>;
|
|
||||||
|
|
||||||
pub type SessionHandlers = ();
|
pub type SessionHandlers = ();
|
||||||
|
|
||||||
impl_opaque_keys! {
|
impl_opaque_keys! {
|
||||||
pub struct SessionKeys {}
|
pub struct SessionKeys {}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// This runtime version.
|
/// This runtime version.
|
||||||
pub const VERSION: RuntimeVersion = RuntimeVersion {
|
pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||||
spec_name: create_runtime_str!("cumulus-contracts-parachain"),
|
spec_name: create_runtime_str!("cumulus-contracts-parachain"),
|
||||||
impl_name: create_runtime_str!("cumulus-contracts-parachain"),
|
impl_name: create_runtime_str!("cumulus-contracts-parachain"),
|
||||||
authoring_version: 1,
|
authoring_version: 1,
|
||||||
spec_version: 1,
|
spec_version: 2,
|
||||||
impl_version: 1,
|
impl_version: 1,
|
||||||
apis: RUNTIME_API_VERSIONS,
|
apis: RUNTIME_API_VERSIONS,
|
||||||
transaction_version: 1,
|
transaction_version: 1,
|
||||||
@@ -292,7 +250,7 @@ impl cumulus_pallet_contracts::Trait for Runtime {
|
|||||||
construct_runtime! {
|
construct_runtime! {
|
||||||
pub enum Runtime where
|
pub enum Runtime where
|
||||||
Block = Block,
|
Block = Block,
|
||||||
NodeBlock = opaque::Block,
|
NodeBlock = rococo_parachain_primitives::Block,
|
||||||
UncheckedExtrinsic = UncheckedExtrinsic
|
UncheckedExtrinsic = UncheckedExtrinsic
|
||||||
{
|
{
|
||||||
System: frame_system::{Module, Call, Storage, Config, Event<T>},
|
System: frame_system::{Module, Call, Storage, Config, Event<T>},
|
||||||
@@ -405,11 +363,11 @@ impl_runtime_apis! {
|
|||||||
fn decode_session_keys(
|
fn decode_session_keys(
|
||||||
encoded: Vec<u8>,
|
encoded: Vec<u8>,
|
||||||
) -> Option<Vec<(Vec<u8>, sp_core::crypto::KeyTypeId)>> {
|
) -> Option<Vec<(Vec<u8>, sp_core::crypto::KeyTypeId)>> {
|
||||||
opaque::SessionKeys::decode_into_raw_public_keys(&encoded)
|
SessionKeys::decode_into_raw_public_keys(&encoded)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
|
fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
|
||||||
opaque::SessionKeys::generate(seed)
|
SessionKeys::generate(seed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,9 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use codec::Codec;
|
use codec::Codec;
|
||||||
|
use cumulus_pallet_contracts_primitives::RentProjection;
|
||||||
use jsonrpc_core::{Error, ErrorCode, Result};
|
use jsonrpc_core::{Error, ErrorCode, Result};
|
||||||
use jsonrpc_derive::rpc;
|
use jsonrpc_derive::rpc;
|
||||||
use cumulus_pallet_contracts_primitives::RentProjection;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sp_api::ProvideRuntimeApi;
|
use sp_api::ProvideRuntimeApi;
|
||||||
use sp_blockchain::HeaderBackend;
|
use sp_blockchain::HeaderBackend;
|
||||||
@@ -106,7 +106,11 @@ pub enum RpcContractExecResult {
|
|||||||
impl From<ContractExecResult> for RpcContractExecResult {
|
impl From<ContractExecResult> for RpcContractExecResult {
|
||||||
fn from(r: ContractExecResult) -> Self {
|
fn from(r: ContractExecResult) -> Self {
|
||||||
match r {
|
match r {
|
||||||
ContractExecResult::Success { flags, data, gas_consumed } => RpcContractExecResult::Success {
|
ContractExecResult::Success {
|
||||||
|
flags,
|
||||||
|
data,
|
||||||
|
gas_consumed,
|
||||||
|
} => RpcContractExecResult::Success {
|
||||||
flags,
|
flags,
|
||||||
data: data.into(),
|
data: data.into(),
|
||||||
gas_consumed,
|
gas_consumed,
|
||||||
@@ -293,7 +297,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn call_request_should_serialize_deserialize_properly() {
|
fn call_request_should_serialize_deserialize_properly() {
|
||||||
type Req = CallRequest<String, u128>;
|
type Req = CallRequest<String, u128>;
|
||||||
let req: Req = serde_json::from_str(r#"
|
let req: Req = serde_json::from_str(
|
||||||
|
r#"
|
||||||
{
|
{
|
||||||
"origin": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
|
"origin": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
|
||||||
"dest": "5DRakbLVnjVrW6niwLfHGW24EeCEvDAFGEXrtaYS5M4ynoom",
|
"dest": "5DRakbLVnjVrW6niwLfHGW24EeCEvDAFGEXrtaYS5M4ynoom",
|
||||||
@@ -301,7 +306,9 @@ mod tests {
|
|||||||
"gasLimit": 1000000000000,
|
"gasLimit": 1000000000000,
|
||||||
"inputData": "0x8c97db39"
|
"inputData": "0x8c97db39"
|
||||||
}
|
}
|
||||||
"#).unwrap();
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(req.gas_limit.into_u256(), U256::from(0xe8d4a51000u64));
|
assert_eq!(req.gas_limit.into_u256(), U256::from(0xe8d4a51000u64));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,14 +21,19 @@ use super::{
|
|||||||
TrieIdGenerator,
|
TrieIdGenerator,
|
||||||
};
|
};
|
||||||
use crate::exec::StorageKey;
|
use crate::exec::StorageKey;
|
||||||
use sp_std::cell::RefCell;
|
use frame_support::{
|
||||||
use sp_std::collections::btree_map::{BTreeMap, Entry};
|
storage::unhashed as storage,
|
||||||
use sp_std::prelude::*;
|
traits::{Currency, Imbalance, SignedImbalance},
|
||||||
|
StorageMap,
|
||||||
|
};
|
||||||
|
use frame_system;
|
||||||
use sp_io::hashing::blake2_256;
|
use sp_io::hashing::blake2_256;
|
||||||
use sp_runtime::traits::{Bounded, Zero};
|
use sp_runtime::traits::{Bounded, Zero};
|
||||||
use frame_support::traits::{Currency, Imbalance, SignedImbalance};
|
use sp_std::{
|
||||||
use frame_support::{storage::unhashed as storage, StorageMap};
|
cell::RefCell,
|
||||||
use frame_system;
|
collections::btree_map::{BTreeMap, Entry},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
// Note: we don't provide Option<Contract> because we can't create
|
// Note: we don't provide Option<Contract> because we can't create
|
||||||
// the trie_id in the overlay, thus we provide an overlay on the fields
|
// the trie_id in the overlay, thus we provide an overlay on the fields
|
||||||
@@ -133,8 +138,7 @@ impl<T: Trait> AccountDb<T> for DirectAccountDb {
|
|||||||
trie_id: Option<&TrieId>,
|
trie_id: Option<&TrieId>,
|
||||||
location: &StorageKey,
|
location: &StorageKey,
|
||||||
) -> Option<Vec<u8>> {
|
) -> Option<Vec<u8>> {
|
||||||
trie_id
|
trie_id.and_then(|id| storage::get_raw(&crate::prefixed_key(id, &blake2_256(location))))
|
||||||
.and_then(|id| storage::get_raw(&crate::prefixed_key(id, &blake2_256(location))))
|
|
||||||
}
|
}
|
||||||
fn get_code_hash(&self, account: &T::AccountId) -> Option<CodeHash<T>> {
|
fn get_code_hash(&self, account: &T::AccountId) -> Option<CodeHash<T>> {
|
||||||
<ContractInfoOf<T>>::get(account).and_then(|i| i.as_alive().map(|i| i.code_hash))
|
<ContractInfoOf<T>>::get(account).and_then(|i| i.as_alive().map(|i| i.code_hash))
|
||||||
@@ -241,13 +245,13 @@ impl<T: Trait> AccountDb<T> for DirectAccountDb {
|
|||||||
if prev_value.is_empty() {
|
if prev_value.is_empty() {
|
||||||
new_info.empty_pair_count -= 1;
|
new_info.empty_pair_count -= 1;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
(None, Some(new_value)) => {
|
(None, Some(new_value)) => {
|
||||||
new_info.total_pair_count += 1;
|
new_info.total_pair_count += 1;
|
||||||
if new_value.is_empty() {
|
if new_value.is_empty() {
|
||||||
new_info.empty_pair_count += 1;
|
new_info.empty_pair_count += 1;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
(Some(prev_value), Some(new_value)) => {
|
(Some(prev_value), Some(new_value)) => {
|
||||||
if prev_value.is_empty() {
|
if prev_value.is_empty() {
|
||||||
new_info.empty_pair_count -= 1;
|
new_info.empty_pair_count -= 1;
|
||||||
|
|||||||
@@ -14,19 +14,23 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use super::{CodeHash, Config, ContractAddressFor, Event, RawEvent, Trait,
|
use super::{
|
||||||
TrieId, BalanceOf, ContractInfo};
|
BalanceOf, CodeHash, Config, ContractAddressFor, ContractInfo, Event, RawEvent, Trait, TrieId,
|
||||||
use crate::account_db::{AccountDb, DirectAccountDb, OverlayAccountDb};
|
};
|
||||||
use crate::gas::{Gas, GasMeter, Token};
|
use crate::{
|
||||||
use crate::rent;
|
account_db::{AccountDb, DirectAccountDb, OverlayAccountDb},
|
||||||
|
gas::{Gas, GasMeter, Token},
|
||||||
|
rent,
|
||||||
|
};
|
||||||
|
|
||||||
use sp_std::prelude::*;
|
|
||||||
use sp_runtime::traits::{Bounded, Zero, Convert, CheckedSub, CheckedAdd};
|
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
storage::unhashed, dispatch::DispatchError,
|
dispatch::DispatchError,
|
||||||
traits::{Currency, Time, Randomness, WithdrawReason},
|
storage::unhashed,
|
||||||
|
traits::{Currency, Randomness, Time, WithdrawReason},
|
||||||
weights::Weight,
|
weights::Weight,
|
||||||
};
|
};
|
||||||
|
use sp_runtime::traits::{Bounded, CheckedAdd, CheckedSub, Convert, Zero};
|
||||||
|
use sp_std::prelude::*;
|
||||||
|
|
||||||
pub type AccountIdOf<T> = <T as frame_system::Trait>::AccountId;
|
pub type AccountIdOf<T> = <T as frame_system::Trait>::AccountId;
|
||||||
pub type CallOf<T> = <T as Trait>::Call;
|
pub type CallOf<T> = <T as Trait>::Call;
|
||||||
@@ -84,11 +88,14 @@ macro_rules! try_or_exec_error {
|
|||||||
($e:expr, $buffer:expr) => {
|
($e:expr, $buffer:expr) => {
|
||||||
match $e {
|
match $e {
|
||||||
Ok(val) => val,
|
Ok(val) => val,
|
||||||
Err(reason) => return Err(
|
Err(reason) => {
|
||||||
$crate::exec::ExecError { reason: reason.into(), buffer: $buffer }
|
return Err($crate::exec::ExecError {
|
||||||
),
|
reason: reason.into(),
|
||||||
|
buffer: $buffer,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An interface that provides access to the external environment in which the
|
/// An interface that provides access to the external environment in which the
|
||||||
@@ -332,9 +339,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nested<'b, 'c: 'b>(&'c self, dest: T::AccountId, trie_id: Option<TrieId>)
|
fn nested<'b, 'c: 'b>(
|
||||||
-> ExecutionContext<'b, T, V, L>
|
&'c self,
|
||||||
{
|
dest: T::AccountId,
|
||||||
|
trie_id: Option<TrieId>,
|
||||||
|
) -> ExecutionContext<'b, T, V, L> {
|
||||||
ExecutionContext {
|
ExecutionContext {
|
||||||
caller: Some(self),
|
caller: Some(self),
|
||||||
self_trie_id: trie_id,
|
self_trie_id: trie_id,
|
||||||
@@ -355,7 +364,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
dest: T::AccountId,
|
dest: T::AccountId,
|
||||||
value: BalanceOf<T>,
|
value: BalanceOf<T>,
|
||||||
gas_meter: &mut GasMeter<T>
|
gas_meter: &mut GasMeter<T>,
|
||||||
) -> Result<(), DispatchError> {
|
) -> Result<(), DispatchError> {
|
||||||
transfer(
|
transfer(
|
||||||
gas_meter,
|
gas_meter,
|
||||||
@@ -427,12 +436,9 @@ where
|
|||||||
// it is a regular account since tombstone accounts have already been rejected.
|
// it is a regular account since tombstone accounts have already been rejected.
|
||||||
match nested.overlay.get_code_hash(&dest) {
|
match nested.overlay.get_code_hash(&dest) {
|
||||||
Some(dest_code_hash) => {
|
Some(dest_code_hash) => {
|
||||||
let executable = try_or_exec_error!(
|
let executable =
|
||||||
nested.loader.load_main(&dest_code_hash),
|
try_or_exec_error!(nested.loader.load_main(&dest_code_hash), input_data);
|
||||||
input_data
|
let output = nested.vm.execute(
|
||||||
);
|
|
||||||
let output = nested.vm
|
|
||||||
.execute(
|
|
||||||
&executable,
|
&executable,
|
||||||
nested.new_call_context(caller, value),
|
nested.new_call_context(caller, value),
|
||||||
input_data,
|
input_data,
|
||||||
@@ -441,7 +447,10 @@ where
|
|||||||
|
|
||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
None => Ok(ExecReturnValue { status: STATUS_SUCCESS, data: Vec::new() }),
|
None => Ok(ExecReturnValue {
|
||||||
|
status: STATUS_SUCCESS,
|
||||||
|
data: Vec::new(),
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -471,18 +480,17 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
let caller = self.self_account.clone();
|
let caller = self.self_account.clone();
|
||||||
let dest = T::DetermineContractAddress::contract_address_for(
|
let dest =
|
||||||
code_hash,
|
T::DetermineContractAddress::contract_address_for(code_hash, &input_data, &caller);
|
||||||
&input_data,
|
|
||||||
&caller,
|
|
||||||
);
|
|
||||||
|
|
||||||
// TrieId has not been generated yet and storage is empty since contract is new.
|
// TrieId has not been generated yet and storage is empty since contract is new.
|
||||||
let dest_trie_id = None;
|
let dest_trie_id = None;
|
||||||
|
|
||||||
let output = self.with_nested_context(dest.clone(), dest_trie_id, |nested| {
|
let output = self.with_nested_context(dest.clone(), dest_trie_id, |nested| {
|
||||||
try_or_exec_error!(
|
try_or_exec_error!(
|
||||||
nested.overlay.instantiate_contract(&dest, code_hash.clone()),
|
nested
|
||||||
|
.overlay
|
||||||
|
.instantiate_contract(&dest, code_hash.clone()),
|
||||||
input_data
|
input_data
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -500,12 +508,8 @@ where
|
|||||||
input_data
|
input_data
|
||||||
);
|
);
|
||||||
|
|
||||||
let executable = try_or_exec_error!(
|
let executable = try_or_exec_error!(nested.loader.load_init(&code_hash), input_data);
|
||||||
nested.loader.load_init(&code_hash),
|
let output = nested.vm.execute(
|
||||||
input_data
|
|
||||||
);
|
|
||||||
let output = nested.vm
|
|
||||||
.execute(
|
|
||||||
&executable,
|
&executable,
|
||||||
nested.new_call_context(caller.clone(), endowment),
|
nested.new_call_context(caller.clone(), endowment),
|
||||||
input_data,
|
input_data,
|
||||||
@@ -574,9 +578,14 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_nested_context<F>(&mut self, dest: T::AccountId, trie_id: Option<TrieId>, func: F)
|
fn with_nested_context<F>(
|
||||||
-> ExecResult
|
&mut self,
|
||||||
where F: FnOnce(&mut ExecutionContext<T, V, L>) -> ExecResult
|
dest: T::AccountId,
|
||||||
|
trie_id: Option<TrieId>,
|
||||||
|
func: F,
|
||||||
|
) -> ExecResult
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut ExecutionContext<T, V, L>) -> ExecResult,
|
||||||
{
|
{
|
||||||
let (output, change_set, deferred) = {
|
let (output, change_set, deferred) = {
|
||||||
let mut nested = self.nested(dest, trie_id);
|
let mut nested = self.nested(dest, trie_id);
|
||||||
@@ -595,8 +604,7 @@ where
|
|||||||
/// Returns whether a contract, identified by address, is currently live in the execution
|
/// Returns whether a contract, identified by address, is currently live in the execution
|
||||||
/// stack, meaning it is in the middle of an execution.
|
/// stack, meaning it is in the middle of an execution.
|
||||||
fn is_live(&self, account: &T::AccountId) -> bool {
|
fn is_live(&self, account: &T::AccountId) -> bool {
|
||||||
&self.self_account == account ||
|
&self.self_account == account || self.caller.map_or(false, |caller| caller.is_live(account))
|
||||||
self.caller.map_or(false, |caller| caller.is_live(account))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,8 +664,7 @@ fn transfer<'a, T: Trait, V: Vm<T>, L: Loader<T>>(
|
|||||||
value: BalanceOf<T>,
|
value: BalanceOf<T>,
|
||||||
ctx: &mut ExecutionContext<'a, T, V, L>,
|
ctx: &mut ExecutionContext<'a, T, V, L>,
|
||||||
) -> Result<(), DispatchError> {
|
) -> Result<(), DispatchError> {
|
||||||
use self::TransferCause::*;
|
use self::{TransferCause::*, TransferFeeKind::*};
|
||||||
use self::TransferFeeKind::*;
|
|
||||||
|
|
||||||
let token = {
|
let token = {
|
||||||
let kind: TransferFeeKind = match cause {
|
let kind: TransferFeeKind = match cause {
|
||||||
@@ -668,9 +675,7 @@ fn transfer<'a, T: Trait, V: Vm<T>, L: Loader<T>>(
|
|||||||
// Otherwise the fee is to transfer to an account.
|
// Otherwise the fee is to transfer to an account.
|
||||||
Call | Terminate => TransferFeeKind::Transfer,
|
Call | Terminate => TransferFeeKind::Transfer,
|
||||||
};
|
};
|
||||||
TransferFeeToken {
|
TransferFeeToken { kind }
|
||||||
kind,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if gas_meter.charge(ctx.config, token).is_out_of_gas() {
|
if gas_meter.charge(ctx.config, token).is_out_of_gas() {
|
||||||
@@ -691,14 +696,15 @@ fn transfer<'a, T: Trait, V: Vm<T>, L: Loader<T>>(
|
|||||||
// Only ext_terminate is allowed to bring the sender below the existential deposit
|
// Only ext_terminate is allowed to bring the sender below the existential deposit
|
||||||
let required_balance = match cause {
|
let required_balance = match cause {
|
||||||
Terminate => 0.into(),
|
Terminate => 0.into(),
|
||||||
_ => ctx.config.existential_deposit
|
_ => ctx.config.existential_deposit,
|
||||||
};
|
};
|
||||||
|
|
||||||
T::Currency::ensure_can_withdraw(
|
T::Currency::ensure_can_withdraw(
|
||||||
transactor,
|
transactor,
|
||||||
value,
|
value,
|
||||||
WithdrawReason::Transfer.into(),
|
WithdrawReason::Transfer.into(),
|
||||||
new_from_balance.checked_sub(&required_balance)
|
new_from_balance
|
||||||
|
.checked_sub(&required_balance)
|
||||||
.ok_or("brings sender below existential deposit")?,
|
.ok_or("brings sender below existential deposit")?,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -736,7 +742,9 @@ where
|
|||||||
type T = T;
|
type T = T;
|
||||||
|
|
||||||
fn get_storage(&self, key: &StorageKey) -> Option<Vec<u8>> {
|
fn get_storage(&self, key: &StorageKey) -> Option<Vec<u8>> {
|
||||||
self.ctx.overlay.get_storage(&self.ctx.self_account, self.ctx.self_trie_id.as_ref(), key)
|
self.ctx
|
||||||
|
.overlay
|
||||||
|
.get_storage(&self.ctx.self_account, self.ctx.self_trie_id.as_ref(), key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_storage(&mut self, key: StorageKey, value: Option<Vec<u8>>) -> Result<(), &'static str> {
|
fn set_storage(&mut self, key: StorageKey, value: Option<Vec<u8>>) -> Result<(), &'static str> {
|
||||||
@@ -759,7 +767,8 @@ where
|
|||||||
gas_meter: &mut GasMeter<T>,
|
gas_meter: &mut GasMeter<T>,
|
||||||
input_data: Vec<u8>,
|
input_data: Vec<u8>,
|
||||||
) -> Result<(AccountIdOf<T>, ExecReturnValue), ExecError> {
|
) -> Result<(AccountIdOf<T>, ExecReturnValue), ExecError> {
|
||||||
self.ctx.instantiate(endowment, gas_meter, code_hash, input_data)
|
self.ctx
|
||||||
|
.instantiate(endowment, gas_meter, code_hash, input_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transfer(
|
fn transfer(
|
||||||
@@ -852,15 +861,21 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_rent_allowance(&mut self, rent_allowance: BalanceOf<T>) {
|
fn set_rent_allowance(&mut self, rent_allowance: BalanceOf<T>) {
|
||||||
self.ctx.overlay.set_rent_allowance(&self.ctx.self_account, rent_allowance)
|
self.ctx
|
||||||
|
.overlay
|
||||||
|
.set_rent_allowance(&self.ctx.self_account, rent_allowance)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rent_allowance(&self) -> BalanceOf<T> {
|
fn rent_allowance(&self) -> BalanceOf<T> {
|
||||||
self.ctx.overlay.get_rent_allowance(&self.ctx.self_account)
|
self.ctx
|
||||||
|
.overlay
|
||||||
|
.get_rent_allowance(&self.ctx.self_account)
|
||||||
.unwrap_or(<BalanceOf<T>>::max_value()) // Must never be triggered actually
|
.unwrap_or(<BalanceOf<T>>::max_value()) // Must never be triggered actually
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_number(&self) -> T::BlockNumber { self.block_number }
|
fn block_number(&self) -> T::BlockNumber {
|
||||||
|
self.block_number
|
||||||
|
}
|
||||||
|
|
||||||
fn max_value_size(&self) -> u32 {
|
fn max_value_size(&self) -> u32 {
|
||||||
self.ctx.config.max_value_size
|
self.ctx.config.max_value_size
|
||||||
@@ -888,17 +903,19 @@ where
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{
|
use super::{
|
||||||
BalanceOf, ExecFeeToken, ExecutionContext, Ext, Loader, TransferFeeKind, TransferFeeToken,
|
BalanceOf, DeferredAction, ExecFeeToken, ExecResult, ExecutionContext, Ext, Loader,
|
||||||
Vm, ExecResult, RawEvent, DeferredAction,
|
RawEvent, TransferFeeKind, TransferFeeToken, Vm,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
account_db::AccountDb, gas::GasMeter, tests::{ExtBuilder, Test},
|
account_db::AccountDb,
|
||||||
exec::{ExecReturnValue, ExecError, STATUS_SUCCESS}, CodeHash, Config,
|
exec::{ExecError, ExecReturnValue, STATUS_SUCCESS},
|
||||||
gas::Gas,
|
gas::{Gas, GasMeter},
|
||||||
|
tests::{ExtBuilder, Test},
|
||||||
|
CodeHash, Config,
|
||||||
};
|
};
|
||||||
use std::{cell::RefCell, rc::Rc, collections::HashMap, marker::PhantomData};
|
|
||||||
use assert_matches::assert_matches;
|
use assert_matches::assert_matches;
|
||||||
use sp_runtime::DispatchError;
|
use sp_runtime::DispatchError;
|
||||||
|
use std::{cell::RefCell, collections::HashMap, marker::PhantomData, rc::Rc};
|
||||||
|
|
||||||
const ALICE: u64 = 1;
|
const ALICE: u64 = 1;
|
||||||
const BOB: u64 = 2;
|
const BOB: u64 = 2;
|
||||||
@@ -907,7 +924,8 @@ mod tests {
|
|||||||
const GAS_LIMIT: Gas = 10_000_000_000;
|
const GAS_LIMIT: Gas = 10_000_000_000;
|
||||||
|
|
||||||
impl<'a, T, V, L> ExecutionContext<'a, T, V, L>
|
impl<'a, T, V, L> ExecutionContext<'a, T, V, L>
|
||||||
where T: crate::Trait
|
where
|
||||||
|
T: crate::Trait,
|
||||||
{
|
{
|
||||||
fn events(&self) -> Vec<DeferredAction<T>> {
|
fn events(&self) -> Vec<DeferredAction<T>> {
|
||||||
self.deferred
|
self.deferred
|
||||||
@@ -965,7 +983,9 @@ mod tests {
|
|||||||
|
|
||||||
impl<'a> MockVm<'a> {
|
impl<'a> MockVm<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
MockVm { _marker: PhantomData }
|
MockVm {
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1005,7 +1025,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn exec_success() -> ExecResult {
|
fn exec_success() -> ExecResult {
|
||||||
Ok(ExecReturnValue { status: STATUS_SUCCESS, data: Vec::new() })
|
Ok(ExecReturnValue {
|
||||||
|
status: STATUS_SUCCESS,
|
||||||
|
data: Vec::new(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1029,10 +1052,7 @@ mod tests {
|
|||||||
let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader);
|
let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader);
|
||||||
ctx.overlay.instantiate_contract(&BOB, exec_ch).unwrap();
|
ctx.overlay.instantiate_contract(&BOB, exec_ch).unwrap();
|
||||||
|
|
||||||
assert_matches!(
|
assert_matches!(ctx.call(BOB, value, &mut gas_meter, data), Ok(_));
|
||||||
ctx.call(BOB, value, &mut gas_meter, data),
|
|
||||||
Ok(_)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(&*test_data.borrow(), &vec![0, 1]);
|
assert_eq!(&*test_data.borrow(), &vec![0, 1]);
|
||||||
@@ -1098,12 +1118,9 @@ mod tests {
|
|||||||
ctx.overlay.set_balance(&origin, 100);
|
ctx.overlay.set_balance(&origin, 100);
|
||||||
ctx.overlay.set_balance(&dest, 0);
|
ctx.overlay.set_balance(&dest, 0);
|
||||||
|
|
||||||
let output = ctx.call(
|
let output = ctx
|
||||||
dest,
|
.call(dest, 55, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![])
|
||||||
55,
|
.unwrap();
|
||||||
&mut GasMeter::<Test>::new(GAS_LIMIT),
|
|
||||||
vec![],
|
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
assert!(output.is_success());
|
assert!(output.is_success());
|
||||||
assert_eq!(ctx.overlay.get_balance(&origin), 45);
|
assert_eq!(ctx.overlay.get_balance(&origin), 45);
|
||||||
@@ -1120,9 +1137,12 @@ mod tests {
|
|||||||
|
|
||||||
let vm = MockVm::new();
|
let vm = MockVm::new();
|
||||||
let mut loader = MockLoader::empty();
|
let mut loader = MockLoader::empty();
|
||||||
let return_ch = loader.insert(
|
let return_ch = loader.insert(|_| {
|
||||||
|_| Ok(ExecReturnValue { status: 1, data: Vec::new() })
|
Ok(ExecReturnValue {
|
||||||
);
|
status: 1,
|
||||||
|
data: Vec::new(),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
ExtBuilder::default().build().execute_with(|| {
|
ExtBuilder::default().build().execute_with(|| {
|
||||||
let cfg = Config::preload();
|
let cfg = Config::preload();
|
||||||
@@ -1131,12 +1151,9 @@ mod tests {
|
|||||||
ctx.overlay.set_balance(&origin, 100);
|
ctx.overlay.set_balance(&origin, 100);
|
||||||
ctx.overlay.set_balance(&dest, 0);
|
ctx.overlay.set_balance(&dest, 0);
|
||||||
|
|
||||||
let output = ctx.call(
|
let output = ctx
|
||||||
dest,
|
.call(dest, 55, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![])
|
||||||
55,
|
.unwrap();
|
||||||
&mut GasMeter::<Test>::new(GAS_LIMIT),
|
|
||||||
vec![],
|
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
assert!(!output.is_success());
|
assert!(!output.is_success());
|
||||||
assert_eq!(ctx.overlay.get_balance(&origin), 100);
|
assert_eq!(ctx.overlay.get_balance(&origin), 100);
|
||||||
@@ -1152,7 +1169,10 @@ mod tests {
|
|||||||
// This test sends 50 units of currency to a non-existent account.
|
// This test sends 50 units of currency to a non-existent account.
|
||||||
// This should lead to creation of a new account thus
|
// This should lead to creation of a new account thus
|
||||||
// a fee should be charged.
|
// a fee should be charged.
|
||||||
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
|
ExtBuilder::default()
|
||||||
|
.existential_deposit(15)
|
||||||
|
.build()
|
||||||
|
.execute_with(|| {
|
||||||
let vm = MockVm::new();
|
let vm = MockVm::new();
|
||||||
let loader = MockLoader::empty();
|
let loader = MockLoader::empty();
|
||||||
let cfg = Config::preload();
|
let cfg = Config::preload();
|
||||||
@@ -1177,7 +1197,10 @@ mod tests {
|
|||||||
|
|
||||||
// This one is similar to the previous one but transfer to an existing account.
|
// This one is similar to the previous one but transfer to an existing account.
|
||||||
// In this test we expect that a regular transfer fee is charged.
|
// In this test we expect that a regular transfer fee is charged.
|
||||||
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
|
ExtBuilder::default()
|
||||||
|
.existential_deposit(15)
|
||||||
|
.build()
|
||||||
|
.execute_with(|| {
|
||||||
let vm = MockVm::new();
|
let vm = MockVm::new();
|
||||||
let loader = MockLoader::empty();
|
let loader = MockLoader::empty();
|
||||||
let cfg = Config::preload();
|
let cfg = Config::preload();
|
||||||
@@ -1202,7 +1225,10 @@ mod tests {
|
|||||||
|
|
||||||
// This test sends 50 units of currency as an endowment to a newly
|
// This test sends 50 units of currency as an endowment to a newly
|
||||||
// instantiated contract.
|
// instantiated contract.
|
||||||
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
|
ExtBuilder::default()
|
||||||
|
.existential_deposit(15)
|
||||||
|
.build()
|
||||||
|
.execute_with(|| {
|
||||||
let mut loader = MockLoader::empty();
|
let mut loader = MockLoader::empty();
|
||||||
let code = loader.insert(|_| exec_success());
|
let code = loader.insert(|_| exec_success());
|
||||||
|
|
||||||
@@ -1244,12 +1270,7 @@ mod tests {
|
|||||||
let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader);
|
let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader);
|
||||||
ctx.overlay.set_balance(&origin, 0);
|
ctx.overlay.set_balance(&origin, 0);
|
||||||
|
|
||||||
let result = ctx.call(
|
let result = ctx.call(dest, 100, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]);
|
||||||
dest,
|
|
||||||
100,
|
|
||||||
&mut GasMeter::<Test>::new(GAS_LIMIT),
|
|
||||||
vec![],
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
result,
|
result,
|
||||||
@@ -1272,21 +1293,19 @@ mod tests {
|
|||||||
|
|
||||||
let vm = MockVm::new();
|
let vm = MockVm::new();
|
||||||
let mut loader = MockLoader::empty();
|
let mut loader = MockLoader::empty();
|
||||||
let return_ch = loader.insert(
|
let return_ch = loader.insert(|_| {
|
||||||
|_| Ok(ExecReturnValue { status: STATUS_SUCCESS, data: vec![1, 2, 3, 4] })
|
Ok(ExecReturnValue {
|
||||||
);
|
status: STATUS_SUCCESS,
|
||||||
|
data: vec![1, 2, 3, 4],
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
ExtBuilder::default().build().execute_with(|| {
|
ExtBuilder::default().build().execute_with(|| {
|
||||||
let cfg = Config::preload();
|
let cfg = Config::preload();
|
||||||
let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader);
|
let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader);
|
||||||
ctx.overlay.instantiate_contract(&BOB, return_ch).unwrap();
|
ctx.overlay.instantiate_contract(&BOB, return_ch).unwrap();
|
||||||
|
|
||||||
let result = ctx.call(
|
let result = ctx.call(dest, 0, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]);
|
||||||
dest,
|
|
||||||
0,
|
|
||||||
&mut GasMeter::<Test>::new(GAS_LIMIT),
|
|
||||||
vec![],
|
|
||||||
);
|
|
||||||
|
|
||||||
let output = result.unwrap();
|
let output = result.unwrap();
|
||||||
assert!(output.is_success());
|
assert!(output.is_success());
|
||||||
@@ -1303,21 +1322,19 @@ mod tests {
|
|||||||
|
|
||||||
let vm = MockVm::new();
|
let vm = MockVm::new();
|
||||||
let mut loader = MockLoader::empty();
|
let mut loader = MockLoader::empty();
|
||||||
let return_ch = loader.insert(
|
let return_ch = loader.insert(|_| {
|
||||||
|_| Ok(ExecReturnValue { status: 1, data: vec![1, 2, 3, 4] })
|
Ok(ExecReturnValue {
|
||||||
);
|
status: 1,
|
||||||
|
data: vec![1, 2, 3, 4],
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
ExtBuilder::default().build().execute_with(|| {
|
ExtBuilder::default().build().execute_with(|| {
|
||||||
let cfg = Config::preload();
|
let cfg = Config::preload();
|
||||||
let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader);
|
let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader);
|
||||||
ctx.overlay.instantiate_contract(&BOB, return_ch).unwrap();
|
ctx.overlay.instantiate_contract(&BOB, return_ch).unwrap();
|
||||||
|
|
||||||
let result = ctx.call(
|
let result = ctx.call(dest, 0, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]);
|
||||||
dest,
|
|
||||||
0,
|
|
||||||
&mut GasMeter::<Test>::new(GAS_LIMIT),
|
|
||||||
vec![],
|
|
||||||
);
|
|
||||||
|
|
||||||
let output = result.unwrap();
|
let output = result.unwrap();
|
||||||
assert!(!output.is_success());
|
assert!(!output.is_success());
|
||||||
@@ -1338,7 +1355,9 @@ mod tests {
|
|||||||
ExtBuilder::default().build().execute_with(|| {
|
ExtBuilder::default().build().execute_with(|| {
|
||||||
let cfg = Config::preload();
|
let cfg = Config::preload();
|
||||||
let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader);
|
let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader);
|
||||||
ctx.overlay.instantiate_contract(&BOB, input_data_ch).unwrap();
|
ctx.overlay
|
||||||
|
.instantiate_contract(&BOB, input_data_ch)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let result = ctx.call(
|
let result = ctx.call(
|
||||||
BOB,
|
BOB,
|
||||||
@@ -1415,12 +1434,7 @@ mod tests {
|
|||||||
ctx.overlay.set_balance(&BOB, 1);
|
ctx.overlay.set_balance(&BOB, 1);
|
||||||
ctx.overlay.instantiate_contract(&BOB, recurse_ch).unwrap();
|
ctx.overlay.instantiate_contract(&BOB, recurse_ch).unwrap();
|
||||||
|
|
||||||
let result = ctx.call(
|
let result = ctx.call(BOB, value, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]);
|
||||||
BOB,
|
|
||||||
value,
|
|
||||||
&mut GasMeter::<Test>::new(GAS_LIMIT),
|
|
||||||
vec![],
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_matches!(result, Ok(_));
|
assert_matches!(result, Ok(_));
|
||||||
});
|
});
|
||||||
@@ -1442,10 +1456,7 @@ mod tests {
|
|||||||
*witnessed_caller_bob.borrow_mut() = Some(*ctx.ext.caller());
|
*witnessed_caller_bob.borrow_mut() = Some(*ctx.ext.caller());
|
||||||
|
|
||||||
// Call into CHARLIE contract.
|
// Call into CHARLIE contract.
|
||||||
assert_matches!(
|
assert_matches!(ctx.ext.call(&CHARLIE, 0, ctx.gas_meter, vec![]), Ok(_));
|
||||||
ctx.ext.call(&CHARLIE, 0, ctx.gas_meter, vec![]),
|
|
||||||
Ok(_)
|
|
||||||
);
|
|
||||||
exec_success()
|
exec_success()
|
||||||
});
|
});
|
||||||
let charlie_ch = loader.insert(|ctx| {
|
let charlie_ch = loader.insert(|ctx| {
|
||||||
@@ -1459,14 +1470,11 @@ mod tests {
|
|||||||
|
|
||||||
let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader);
|
let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader);
|
||||||
ctx.overlay.instantiate_contract(&dest, bob_ch).unwrap();
|
ctx.overlay.instantiate_contract(&dest, bob_ch).unwrap();
|
||||||
ctx.overlay.instantiate_contract(&CHARLIE, charlie_ch).unwrap();
|
ctx.overlay
|
||||||
|
.instantiate_contract(&CHARLIE, charlie_ch)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let result = ctx.call(
|
let result = ctx.call(dest, 0, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]);
|
||||||
dest,
|
|
||||||
0,
|
|
||||||
&mut GasMeter::<Test>::new(GAS_LIMIT),
|
|
||||||
vec![],
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_matches!(result, Ok(_));
|
assert_matches!(result, Ok(_));
|
||||||
});
|
});
|
||||||
@@ -1485,10 +1493,7 @@ mod tests {
|
|||||||
assert_eq!(*ctx.ext.address(), BOB);
|
assert_eq!(*ctx.ext.address(), BOB);
|
||||||
|
|
||||||
// Call into charlie contract.
|
// Call into charlie contract.
|
||||||
assert_matches!(
|
assert_matches!(ctx.ext.call(&CHARLIE, 0, ctx.gas_meter, vec![]), Ok(_));
|
||||||
ctx.ext.call(&CHARLIE, 0, ctx.gas_meter, vec![]),
|
|
||||||
Ok(_)
|
|
||||||
);
|
|
||||||
exec_success()
|
exec_success()
|
||||||
});
|
});
|
||||||
let charlie_ch = loader.insert(|ctx| {
|
let charlie_ch = loader.insert(|ctx| {
|
||||||
@@ -1500,14 +1505,11 @@ mod tests {
|
|||||||
let cfg = Config::preload();
|
let cfg = Config::preload();
|
||||||
let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader);
|
let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader);
|
||||||
ctx.overlay.instantiate_contract(&BOB, bob_ch).unwrap();
|
ctx.overlay.instantiate_contract(&BOB, bob_ch).unwrap();
|
||||||
ctx.overlay.instantiate_contract(&CHARLIE, charlie_ch).unwrap();
|
ctx.overlay
|
||||||
|
.instantiate_contract(&CHARLIE, charlie_ch)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let result = ctx.call(
|
let result = ctx.call(BOB, 0, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]);
|
||||||
BOB,
|
|
||||||
0,
|
|
||||||
&mut GasMeter::<Test>::new(GAS_LIMIT),
|
|
||||||
vec![],
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_matches!(result, Ok(_));
|
assert_matches!(result, Ok(_));
|
||||||
});
|
});
|
||||||
@@ -1520,7 +1522,10 @@ mod tests {
|
|||||||
let mut loader = MockLoader::empty();
|
let mut loader = MockLoader::empty();
|
||||||
let dummy_ch = loader.insert(|_| exec_success());
|
let dummy_ch = loader.insert(|_| exec_success());
|
||||||
|
|
||||||
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
|
ExtBuilder::default()
|
||||||
|
.existential_deposit(15)
|
||||||
|
.build()
|
||||||
|
.execute_with(|| {
|
||||||
let cfg = Config::preload();
|
let cfg = Config::preload();
|
||||||
let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader);
|
let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader);
|
||||||
|
|
||||||
@@ -1541,11 +1546,17 @@ mod tests {
|
|||||||
let vm = MockVm::new();
|
let vm = MockVm::new();
|
||||||
|
|
||||||
let mut loader = MockLoader::empty();
|
let mut loader = MockLoader::empty();
|
||||||
let dummy_ch = loader.insert(
|
let dummy_ch = loader.insert(|_| {
|
||||||
|_| Ok(ExecReturnValue { status: STATUS_SUCCESS, data: vec![80, 65, 83, 83] })
|
Ok(ExecReturnValue {
|
||||||
);
|
status: STATUS_SUCCESS,
|
||||||
|
data: vec![80, 65, 83, 83],
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
|
ExtBuilder::default()
|
||||||
|
.existential_deposit(15)
|
||||||
|
.build()
|
||||||
|
.execute_with(|| {
|
||||||
let cfg = Config::preload();
|
let cfg = Config::preload();
|
||||||
let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader);
|
let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader);
|
||||||
ctx.overlay.set_balance(&ALICE, 1000);
|
ctx.overlay.set_balance(&ALICE, 1000);
|
||||||
@@ -1562,8 +1573,15 @@ mod tests {
|
|||||||
|
|
||||||
// Check that the newly created account has the expected code hash and
|
// Check that the newly created account has the expected code hash and
|
||||||
// there are instantiation event.
|
// there are instantiation event.
|
||||||
assert_eq!(ctx.overlay.get_code_hash(&instantiated_contract_address).unwrap(), dummy_ch);
|
assert_eq!(
|
||||||
assert_eq!(&ctx.events(), &[
|
ctx.overlay
|
||||||
|
.get_code_hash(&instantiated_contract_address)
|
||||||
|
.unwrap(),
|
||||||
|
dummy_ch
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
&ctx.events(),
|
||||||
|
&[
|
||||||
DeferredAction::DepositEvent {
|
DeferredAction::DepositEvent {
|
||||||
event: RawEvent::Transfer(ALICE, instantiated_contract_address, 100),
|
event: RawEvent::Transfer(ALICE, instantiated_contract_address, 100),
|
||||||
topics: Vec::new(),
|
topics: Vec::new(),
|
||||||
@@ -1572,7 +1590,8 @@ mod tests {
|
|||||||
event: RawEvent::Instantiated(ALICE, instantiated_contract_address),
|
event: RawEvent::Instantiated(ALICE, instantiated_contract_address),
|
||||||
topics: Vec::new(),
|
topics: Vec::new(),
|
||||||
}
|
}
|
||||||
]);
|
]
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1581,11 +1600,17 @@ mod tests {
|
|||||||
let vm = MockVm::new();
|
let vm = MockVm::new();
|
||||||
|
|
||||||
let mut loader = MockLoader::empty();
|
let mut loader = MockLoader::empty();
|
||||||
let dummy_ch = loader.insert(
|
let dummy_ch = loader.insert(|_| {
|
||||||
|_| Ok(ExecReturnValue { status: 1, data: vec![70, 65, 73, 76] })
|
Ok(ExecReturnValue {
|
||||||
);
|
status: 1,
|
||||||
|
data: vec![70, 65, 73, 76],
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
|
ExtBuilder::default()
|
||||||
|
.existential_deposit(15)
|
||||||
|
.build()
|
||||||
|
.execute_with(|| {
|
||||||
let cfg = Config::preload();
|
let cfg = Config::preload();
|
||||||
let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader);
|
let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader);
|
||||||
ctx.overlay.set_balance(&ALICE, 1000);
|
ctx.overlay.set_balance(&ALICE, 1000);
|
||||||
@@ -1601,7 +1626,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Check that the account has not been created.
|
// Check that the account has not been created.
|
||||||
assert!(ctx.overlay.get_code_hash(&instantiated_contract_address).is_none());
|
assert!(ctx
|
||||||
|
.overlay
|
||||||
|
.get_code_hash(&instantiated_contract_address)
|
||||||
|
.is_none());
|
||||||
assert!(ctx.events().is_empty());
|
assert!(ctx.events().is_empty());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1618,36 +1646,50 @@ mod tests {
|
|||||||
let instantiated_contract_address = Rc::clone(&instantiated_contract_address);
|
let instantiated_contract_address = Rc::clone(&instantiated_contract_address);
|
||||||
move |ctx| {
|
move |ctx| {
|
||||||
// Instantiate a contract and save it's address in `instantiated_contract_address`.
|
// Instantiate a contract and save it's address in `instantiated_contract_address`.
|
||||||
let (address, output) = ctx.ext.instantiate(
|
let (address, output) = ctx
|
||||||
&dummy_ch,
|
.ext
|
||||||
15u64,
|
.instantiate(&dummy_ch, 15u64, ctx.gas_meter, vec![])
|
||||||
ctx.gas_meter,
|
.unwrap();
|
||||||
vec![]
|
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
*instantiated_contract_address.borrow_mut() = address.into();
|
*instantiated_contract_address.borrow_mut() = address.into();
|
||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
|
ExtBuilder::default()
|
||||||
|
.existential_deposit(15)
|
||||||
|
.build()
|
||||||
|
.execute_with(|| {
|
||||||
let cfg = Config::preload();
|
let cfg = Config::preload();
|
||||||
let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader);
|
let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader);
|
||||||
ctx.overlay.set_balance(&ALICE, 1000);
|
ctx.overlay.set_balance(&ALICE, 1000);
|
||||||
ctx.overlay.set_balance(&BOB, 100);
|
ctx.overlay.set_balance(&BOB, 100);
|
||||||
ctx.overlay.instantiate_contract(&BOB, instantiator_ch).unwrap();
|
ctx.overlay
|
||||||
|
.instantiate_contract(&BOB, instantiator_ch)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
ctx.call(BOB, 20, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]),
|
ctx.call(BOB, 20, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]),
|
||||||
Ok(_)
|
Ok(_)
|
||||||
);
|
);
|
||||||
|
|
||||||
let instantiated_contract_address = instantiated_contract_address.borrow().as_ref().unwrap().clone();
|
let instantiated_contract_address = instantiated_contract_address
|
||||||
|
.borrow()
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.clone();
|
||||||
|
|
||||||
// Check that the newly created account has the expected code hash and
|
// Check that the newly created account has the expected code hash and
|
||||||
// there are instantiation event.
|
// there are instantiation event.
|
||||||
assert_eq!(ctx.overlay.get_code_hash(&instantiated_contract_address).unwrap(), dummy_ch);
|
assert_eq!(
|
||||||
assert_eq!(&ctx.events(), &[
|
ctx.overlay
|
||||||
|
.get_code_hash(&instantiated_contract_address)
|
||||||
|
.unwrap(),
|
||||||
|
dummy_ch
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
&ctx.events(),
|
||||||
|
&[
|
||||||
DeferredAction::DepositEvent {
|
DeferredAction::DepositEvent {
|
||||||
event: RawEvent::Transfer(ALICE, BOB, 20),
|
event: RawEvent::Transfer(ALICE, BOB, 20),
|
||||||
topics: Vec::new(),
|
topics: Vec::new(),
|
||||||
@@ -1660,7 +1702,8 @@ mod tests {
|
|||||||
event: RawEvent::Instantiated(BOB, instantiated_contract_address),
|
event: RawEvent::Instantiated(BOB, instantiated_contract_address),
|
||||||
topics: Vec::new(),
|
topics: Vec::new(),
|
||||||
},
|
},
|
||||||
]);
|
]
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1669,33 +1712,39 @@ mod tests {
|
|||||||
let vm = MockVm::new();
|
let vm = MockVm::new();
|
||||||
|
|
||||||
let mut loader = MockLoader::empty();
|
let mut loader = MockLoader::empty();
|
||||||
let dummy_ch = loader.insert(
|
let dummy_ch = loader.insert(|_| {
|
||||||
|_| Err(ExecError { reason: "It's a trap!".into(), buffer: Vec::new() })
|
Err(ExecError {
|
||||||
);
|
reason: "It's a trap!".into(),
|
||||||
|
buffer: Vec::new(),
|
||||||
|
})
|
||||||
|
});
|
||||||
let instantiator_ch = loader.insert({
|
let instantiator_ch = loader.insert({
|
||||||
let dummy_ch = dummy_ch.clone();
|
let dummy_ch = dummy_ch.clone();
|
||||||
move |ctx| {
|
move |ctx| {
|
||||||
// Instantiate a contract and save it's address in `instantiated_contract_address`.
|
// Instantiate a contract and save it's address in `instantiated_contract_address`.
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
ctx.ext.instantiate(
|
ctx.ext.instantiate(&dummy_ch, 15u64, ctx.gas_meter, vec![]),
|
||||||
&dummy_ch,
|
Err(ExecError {
|
||||||
15u64,
|
reason: DispatchError::Other("It's a trap!"),
|
||||||
ctx.gas_meter,
|
buffer: _,
|
||||||
vec![]
|
})
|
||||||
),
|
|
||||||
Err(ExecError { reason: DispatchError::Other("It's a trap!"), buffer: _ })
|
|
||||||
);
|
);
|
||||||
|
|
||||||
exec_success()
|
exec_success()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
|
ExtBuilder::default()
|
||||||
|
.existential_deposit(15)
|
||||||
|
.build()
|
||||||
|
.execute_with(|| {
|
||||||
let cfg = Config::preload();
|
let cfg = Config::preload();
|
||||||
let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader);
|
let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader);
|
||||||
ctx.overlay.set_balance(&ALICE, 1000);
|
ctx.overlay.set_balance(&ALICE, 1000);
|
||||||
ctx.overlay.set_balance(&BOB, 100);
|
ctx.overlay.set_balance(&BOB, 100);
|
||||||
ctx.overlay.instantiate_contract(&BOB, instantiator_ch).unwrap();
|
ctx.overlay
|
||||||
|
.instantiate_contract(&BOB, instantiator_ch)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
ctx.call(BOB, 20, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]),
|
ctx.call(BOB, 20, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]),
|
||||||
@@ -1704,12 +1753,13 @@ mod tests {
|
|||||||
|
|
||||||
// The contract wasn't instantiated so we don't expect to see an instantiation
|
// The contract wasn't instantiated so we don't expect to see an instantiation
|
||||||
// event here.
|
// event here.
|
||||||
assert_eq!(&ctx.events(), &[
|
assert_eq!(
|
||||||
DeferredAction::DepositEvent {
|
&ctx.events(),
|
||||||
|
&[DeferredAction::DepositEvent {
|
||||||
event: RawEvent::Transfer(ALICE, BOB, 20),
|
event: RawEvent::Transfer(ALICE, BOB, 20),
|
||||||
topics: Vec::new(),
|
topics: Vec::new(),
|
||||||
},
|
},]
|
||||||
]);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1745,10 +1795,7 @@ mod tests {
|
|||||||
}) if buffer == Vec::<u8>::new()
|
}) if buffer == Vec::<u8>::new()
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(&ctx.events(), &[]);
|
||||||
&ctx.events(),
|
|
||||||
&[]
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,11 @@
|
|||||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::Trait;
|
use crate::Trait;
|
||||||
use sp_std::marker::PhantomData;
|
|
||||||
use sp_runtime::traits::Zero;
|
|
||||||
use frame_support::dispatch::{
|
use frame_support::dispatch::{
|
||||||
DispatchError, DispatchResultWithPostInfo, PostDispatchInfo, DispatchErrorWithPostInfo,
|
DispatchError, DispatchErrorWithPostInfo, DispatchResultWithPostInfo, PostDispatchInfo,
|
||||||
};
|
};
|
||||||
|
use sp_runtime::traits::Zero;
|
||||||
|
use sp_std::marker::PhantomData;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use std::{any::Any, fmt::Debug};
|
use std::{any::Any, fmt::Debug};
|
||||||
@@ -189,7 +189,8 @@ impl<T: Trait> GasMeter<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Turn this GasMeter into a DispatchResult that contains the actually used gas.
|
/// Turn this GasMeter into a DispatchResult that contains the actually used gas.
|
||||||
pub fn into_dispatch_result<R, E>(self, result: Result<R, E>) -> DispatchResultWithPostInfo where
|
pub fn into_dispatch_result<R, E>(self, result: Result<R, E>) -> DispatchResultWithPostInfo
|
||||||
|
where
|
||||||
E: Into<DispatchError>,
|
E: Into<DispatchError>,
|
||||||
{
|
{
|
||||||
let post_info = PostDispatchInfo {
|
let post_info = PostDispatchInfo {
|
||||||
@@ -199,7 +200,10 @@ impl<T: Trait> GasMeter<T> {
|
|||||||
|
|
||||||
result
|
result
|
||||||
.map(|_| post_info)
|
.map(|_| post_info)
|
||||||
.map_err(|e| DispatchErrorWithPostInfo { post_info, error: e.into() })
|
.map_err(|e| DispatchErrorWithPostInfo {
|
||||||
|
post_info,
|
||||||
|
error: e.into(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -256,7 +260,9 @@ mod tests {
|
|||||||
struct SimpleToken(u64);
|
struct SimpleToken(u64);
|
||||||
impl Token<Test> for SimpleToken {
|
impl Token<Test> for SimpleToken {
|
||||||
type Metadata = ();
|
type Metadata = ();
|
||||||
fn calculate_amount(&self, _metadata: &()) -> u64 { self.0 }
|
fn calculate_amount(&self, _metadata: &()) -> u64 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MultiplierTokenMetadata {
|
struct MultiplierTokenMetadata {
|
||||||
@@ -285,8 +291,10 @@ mod tests {
|
|||||||
fn simple() {
|
fn simple() {
|
||||||
let mut gas_meter = GasMeter::<Test>::new(50000);
|
let mut gas_meter = GasMeter::<Test>::new(50000);
|
||||||
|
|
||||||
let result = gas_meter
|
let result = gas_meter.charge(
|
||||||
.charge(&MultiplierTokenMetadata { multiplier: 3 }, MultiplierToken(10));
|
&MultiplierTokenMetadata { multiplier: 3 },
|
||||||
|
MultiplierToken(10),
|
||||||
|
);
|
||||||
assert!(!result.is_out_of_gas());
|
assert!(!result.is_out_of_gas());
|
||||||
|
|
||||||
assert_eq!(gas_meter.gas_left(), 49_970);
|
assert_eq!(gas_meter.gas_left(), 49_970);
|
||||||
@@ -297,7 +305,10 @@ mod tests {
|
|||||||
let mut gas_meter = GasMeter::<Test>::new(50000);
|
let mut gas_meter = GasMeter::<Test>::new(50000);
|
||||||
assert!(!gas_meter.charge(&(), SimpleToken(1)).is_out_of_gas());
|
assert!(!gas_meter.charge(&(), SimpleToken(1)).is_out_of_gas());
|
||||||
assert!(!gas_meter
|
assert!(!gas_meter
|
||||||
.charge(&MultiplierTokenMetadata { multiplier: 3 }, MultiplierToken(10))
|
.charge(
|
||||||
|
&MultiplierTokenMetadata { multiplier: 3 },
|
||||||
|
MultiplierToken(10)
|
||||||
|
)
|
||||||
.is_out_of_gas());
|
.is_out_of_gas());
|
||||||
|
|
||||||
let mut tokens = gas_meter.tokens()[0..2].iter();
|
let mut tokens = gas_meter.tokens()[0..2].iter();
|
||||||
@@ -327,7 +338,6 @@ mod tests {
|
|||||||
assert!(gas_meter.charge(&(), SimpleToken(1)).is_out_of_gas());
|
assert!(gas_meter.charge(&(), SimpleToken(1)).is_out_of_gas());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Charging the exact amount that the user paid for should be
|
// Charging the exact amount that the user paid for should be
|
||||||
// possible.
|
// possible.
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -84,42 +84,42 @@ mod gas;
|
|||||||
|
|
||||||
mod account_db;
|
mod account_db;
|
||||||
mod exec;
|
mod exec;
|
||||||
mod wasm;
|
|
||||||
mod rent;
|
mod rent;
|
||||||
|
mod wasm;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
use crate::exec::ExecutionContext;
|
use crate::{
|
||||||
use crate::account_db::{AccountDb, DirectAccountDb};
|
account_db::{AccountDb, DirectAccountDb},
|
||||||
use crate::wasm::{WasmLoader, WasmVm};
|
exec::ExecutionContext,
|
||||||
|
wasm::{WasmLoader, WasmVm},
|
||||||
|
};
|
||||||
|
|
||||||
pub use crate::gas::{Gas, GasMeter};
|
pub use crate::{
|
||||||
pub use crate::exec::{ExecResult, ExecReturnValue, ExecError, StatusCode};
|
exec::{ExecError, ExecResult, ExecReturnValue, StatusCode},
|
||||||
|
gas::{Gas, GasMeter},
|
||||||
|
};
|
||||||
|
|
||||||
|
use codec::{Codec, Decode, Encode};
|
||||||
|
use cumulus_pallet_contracts_primitives::{ContractAccessError, RentProjection};
|
||||||
|
use frame_support::{
|
||||||
|
decl_error, decl_event, decl_module, decl_storage,
|
||||||
|
dispatch::{DispatchResult, DispatchResultWithPostInfo, Dispatchable, PostDispatchInfo},
|
||||||
|
parameter_types,
|
||||||
|
traits::{Currency, Get, OnUnbalanced, Randomness, Time},
|
||||||
|
weights::{GetDispatchInfo, Weight},
|
||||||
|
Parameter,
|
||||||
|
};
|
||||||
|
use frame_system::{ensure_root, ensure_signed, RawOrigin};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sp_core::crypto::UncheckedFrom;
|
use sp_core::crypto::UncheckedFrom;
|
||||||
use sp_std::{prelude::*, marker::PhantomData, fmt::Debug};
|
|
||||||
use codec::{Codec, Encode, Decode};
|
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
traits::{
|
traits::{Convert, Hash, MaybeSerializeDeserialize, Member, StaticLookup, Zero},
|
||||||
Hash, StaticLookup, Zero, MaybeSerializeDeserialize, Member, Convert,
|
|
||||||
},
|
|
||||||
RuntimeDebug,
|
RuntimeDebug,
|
||||||
};
|
};
|
||||||
use frame_support::dispatch::{
|
use sp_std::{fmt::Debug, marker::PhantomData, prelude::*};
|
||||||
PostDispatchInfo, DispatchResult, Dispatchable, DispatchResultWithPostInfo
|
|
||||||
};
|
|
||||||
use frame_support::{
|
|
||||||
Parameter, decl_module, decl_event, decl_storage, decl_error,
|
|
||||||
parameter_types,
|
|
||||||
};
|
|
||||||
use frame_support::traits::{OnUnbalanced, Currency, Get, Time, Randomness};
|
|
||||||
use frame_support::weights::GetDispatchInfo;
|
|
||||||
use frame_system::{ensure_signed, RawOrigin, ensure_root};
|
|
||||||
use cumulus_pallet_contracts_primitives::{RentProjection, ContractAccessError};
|
|
||||||
use frame_support::weights::Weight;
|
|
||||||
|
|
||||||
pub type CodeHash<T> = <T as frame_system::Trait>::Hash;
|
pub type CodeHash<T> = <T as frame_system::Trait>::Hash;
|
||||||
pub type TrieId = Vec<u8>;
|
pub type TrieId = Vec<u8>;
|
||||||
@@ -240,9 +240,15 @@ pub struct RawTombstoneContractInfo<H, Hasher>(H, PhantomData<Hasher>);
|
|||||||
|
|
||||||
impl<H, Hasher> RawTombstoneContractInfo<H, Hasher>
|
impl<H, Hasher> RawTombstoneContractInfo<H, Hasher>
|
||||||
where
|
where
|
||||||
H: Member + MaybeSerializeDeserialize+ Debug
|
H: Member
|
||||||
+ AsRef<[u8]> + AsMut<[u8]> + Copy + Default
|
+ MaybeSerializeDeserialize
|
||||||
+ sp_std::hash::Hash + Codec,
|
+ Debug
|
||||||
|
+ AsRef<[u8]>
|
||||||
|
+ AsMut<[u8]>
|
||||||
|
+ Copy
|
||||||
|
+ Default
|
||||||
|
+ sp_std::hash::Hash
|
||||||
|
+ Codec,
|
||||||
Hasher: Hash<Output = H>,
|
Hasher: Hash<Output = H>,
|
||||||
{
|
{
|
||||||
fn new(storage_root: &[u8], code_hash: H) -> Self {
|
fn new(storage_root: &[u8], code_hash: H) -> Self {
|
||||||
@@ -272,7 +278,7 @@ pub struct TrieIdFromParentCounter<T: Trait>(PhantomData<T>);
|
|||||||
/// accountid_counter`.
|
/// accountid_counter`.
|
||||||
impl<T: Trait> TrieIdGenerator<T::AccountId> for TrieIdFromParentCounter<T>
|
impl<T: Trait> TrieIdGenerator<T::AccountId> for TrieIdFromParentCounter<T>
|
||||||
where
|
where
|
||||||
T::AccountId: AsRef<[u8]>
|
T::AccountId: AsRef<[u8]>,
|
||||||
{
|
{
|
||||||
fn trie_id(account_id: &T::AccountId) -> TrieId {
|
fn trie_id(account_id: &T::AccountId) -> TrieId {
|
||||||
// Note that skipping a value due to error is not an issue here.
|
// Note that skipping a value due to error is not an issue here.
|
||||||
@@ -321,10 +327,9 @@ pub trait Trait: frame_system::Trait {
|
|||||||
type Currency: Currency<Self::AccountId>;
|
type Currency: Currency<Self::AccountId>;
|
||||||
|
|
||||||
/// The outer call dispatch type.
|
/// The outer call dispatch type.
|
||||||
type Call:
|
type Call: Parameter
|
||||||
Parameter +
|
+ Dispatchable<PostInfo = PostDispatchInfo, Origin = <Self as frame_system::Trait>::Origin>
|
||||||
Dispatchable<PostInfo=PostDispatchInfo, Origin=<Self as frame_system::Trait>::Origin> +
|
+ GetDispatchInfo;
|
||||||
GetDispatchInfo;
|
|
||||||
|
|
||||||
/// The overarching event type.
|
/// The overarching event type.
|
||||||
type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
|
type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
|
||||||
@@ -390,9 +395,13 @@ pub trait Trait: frame_system::Trait {
|
|||||||
pub struct SimpleAddressDeterminer<T: Trait>(PhantomData<T>);
|
pub struct SimpleAddressDeterminer<T: Trait>(PhantomData<T>);
|
||||||
impl<T: Trait> ContractAddressFor<CodeHash<T>, T::AccountId> for SimpleAddressDeterminer<T>
|
impl<T: Trait> ContractAddressFor<CodeHash<T>, T::AccountId> for SimpleAddressDeterminer<T>
|
||||||
where
|
where
|
||||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>
|
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||||
{
|
{
|
||||||
fn contract_address_for(code_hash: &CodeHash<T>, data: &[u8], origin: &T::AccountId) -> T::AccountId {
|
fn contract_address_for(
|
||||||
|
code_hash: &CodeHash<T>,
|
||||||
|
data: &[u8],
|
||||||
|
origin: &T::AccountId,
|
||||||
|
) -> T::AccountId {
|
||||||
let data_hash = T::Hashing::hash(data);
|
let data_hash = T::Hashing::hash(data);
|
||||||
|
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
@@ -641,13 +650,15 @@ impl<T: Trait> Module<T> {
|
|||||||
|
|
||||||
impl<T: Trait> Module<T> {
|
impl<T: Trait> Module<T> {
|
||||||
fn calc_code_put_costs(code: &Vec<u8>) -> Gas {
|
fn calc_code_put_costs(code: &Vec<u8>) -> Gas {
|
||||||
<Module<T>>::current_schedule().put_code_per_byte_cost.saturating_mul(code.len() as Gas)
|
<Module<T>>::current_schedule()
|
||||||
|
.put_code_per_byte_cost
|
||||||
|
.saturating_mul(code.len() as Gas)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_wasm(
|
fn execute_wasm(
|
||||||
origin: T::AccountId,
|
origin: T::AccountId,
|
||||||
gas_meter: &mut GasMeter<T>,
|
gas_meter: &mut GasMeter<T>,
|
||||||
func: impl FnOnce(&mut ExecutionContext<T, WasmVm, WasmLoader>, &mut GasMeter<T>) -> ExecResult
|
func: impl FnOnce(&mut ExecutionContext<T, WasmVm, WasmLoader>, &mut GasMeter<T>) -> ExecResult,
|
||||||
) -> ExecResult {
|
) -> ExecResult {
|
||||||
let cfg = Config::preload();
|
let cfg = Config::preload();
|
||||||
let vm = WasmVm::new(&cfg.schedule);
|
let vm = WasmVm::new(&cfg.schedule);
|
||||||
@@ -656,7 +667,11 @@ impl<T: Trait> Module<T> {
|
|||||||
|
|
||||||
let result = func(&mut ctx, gas_meter);
|
let result = func(&mut ctx, gas_meter);
|
||||||
|
|
||||||
if result.as_ref().map(|output| output.is_success()).unwrap_or(false) {
|
if result
|
||||||
|
.as_ref()
|
||||||
|
.map(|output| output.is_success())
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
// Commit all changes that made it thus far into the persistent storage.
|
// Commit all changes that made it thus far into the persistent storage.
|
||||||
DirectAccountDb.commit(ctx.overlay.into_change_set());
|
DirectAccountDb.commit(ctx.overlay.into_change_set());
|
||||||
}
|
}
|
||||||
@@ -665,17 +680,11 @@ impl<T: Trait> Module<T> {
|
|||||||
ctx.deferred.into_iter().for_each(|deferred| {
|
ctx.deferred.into_iter().for_each(|deferred| {
|
||||||
use self::exec::DeferredAction::*;
|
use self::exec::DeferredAction::*;
|
||||||
match deferred {
|
match deferred {
|
||||||
DepositEvent {
|
DepositEvent { topics, event } => <frame_system::Module<T>>::deposit_event_indexed(
|
||||||
topics,
|
|
||||||
event,
|
|
||||||
} => <frame_system::Module<T>>::deposit_event_indexed(
|
|
||||||
&*topics,
|
&*topics,
|
||||||
<T as Trait>::Event::from(event).into(),
|
<T as Trait>::Event::from(event).into(),
|
||||||
),
|
),
|
||||||
DispatchRuntimeCall {
|
DispatchRuntimeCall { origin: who, call } => {
|
||||||
origin: who,
|
|
||||||
call,
|
|
||||||
} => {
|
|
||||||
let info = call.get_dispatch_info();
|
let info = call.get_dispatch_info();
|
||||||
let result = call.dispatch(RawOrigin::Signed(who.clone()).into());
|
let result = call.dispatch(RawOrigin::Signed(who.clone()).into());
|
||||||
let post_info = match result {
|
let post_info = match result {
|
||||||
@@ -693,11 +702,19 @@ impl<T: Trait> Module<T> {
|
|||||||
delta,
|
delta,
|
||||||
} => {
|
} => {
|
||||||
let result = Self::restore_to(
|
let result = Self::restore_to(
|
||||||
donor.clone(), dest.clone(), code_hash.clone(), rent_allowance.clone(), delta
|
donor.clone(),
|
||||||
);
|
dest.clone(),
|
||||||
Self::deposit_event(
|
code_hash.clone(),
|
||||||
RawEvent::Restored(donor, dest, code_hash, rent_allowance, result.is_ok())
|
rent_allowance.clone(),
|
||||||
|
delta,
|
||||||
);
|
);
|
||||||
|
Self::deposit_event(RawEvent::Restored(
|
||||||
|
donor,
|
||||||
|
dest,
|
||||||
|
code_hash,
|
||||||
|
rent_allowance,
|
||||||
|
result.is_ok(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,10 +20,14 @@ use crate::{
|
|||||||
AliveContractInfo, BalanceOf, ContractInfo, ContractInfoOf, Module, RawEvent,
|
AliveContractInfo, BalanceOf, ContractInfo, ContractInfoOf, Module, RawEvent,
|
||||||
TombstoneContractInfo, Trait,
|
TombstoneContractInfo, Trait,
|
||||||
};
|
};
|
||||||
use frame_support::storage::unhashed as storage;
|
use cumulus_pallet_contracts_primitives::{
|
||||||
use frame_support::traits::{Currency, ExistenceRequirement, Get, OnUnbalanced, WithdrawReason};
|
ContractAccessError, RentProjection, RentProjectionResult,
|
||||||
use frame_support::StorageMap;
|
};
|
||||||
use cumulus_pallet_contracts_primitives::{ContractAccessError, RentProjection, RentProjectionResult};
|
use frame_support::{
|
||||||
|
storage::unhashed as storage,
|
||||||
|
traits::{Currency, ExistenceRequirement, Get, OnUnbalanced, WithdrawReason},
|
||||||
|
StorageMap,
|
||||||
|
};
|
||||||
use sp_runtime::traits::{Bounded, CheckedDiv, CheckedMul, SaturatedConversion, Saturating, Zero};
|
use sp_runtime::traits::{Bounded, CheckedDiv, CheckedMul, SaturatedConversion, Saturating, Zero};
|
||||||
|
|
||||||
/// The amount to charge.
|
/// The amount to charge.
|
||||||
@@ -238,10 +242,8 @@ fn enact_verdict<T: Trait>(
|
|||||||
|
|
||||||
// Use a dummy storage root because restoration is currentlyy unsupported
|
// Use a dummy storage root because restoration is currentlyy unsupported
|
||||||
// for parachains anyways.
|
// for parachains anyways.
|
||||||
let tombstone = <TombstoneContractInfo<T>>::new(
|
let tombstone =
|
||||||
&[0u8; 32],
|
<TombstoneContractInfo<T>>::new(&[0u8; 32], alive_contract_info.code_hash);
|
||||||
alive_contract_info.code_hash,
|
|
||||||
);
|
|
||||||
let tombstone_info = ContractInfo::Tombstone(tombstone);
|
let tombstone_info = ContractInfo::Tombstone(tombstone);
|
||||||
<ContractInfoOf<T>>::insert(account, &tombstone_info);
|
<ContractInfoOf<T>>::insert(account, &tombstone_info);
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -26,11 +26,13 @@
|
|||||||
//! this guarantees that every instrumented contract code in cache cannot have the version equal to the current one.
|
//! this guarantees that every instrumented contract code in cache cannot have the version equal to the current one.
|
||||||
//! Thus, before executing a contract it should be reinstrument with new schedule.
|
//! Thus, before executing a contract it should be reinstrument with new schedule.
|
||||||
|
|
||||||
use crate::wasm::{prepare, runtime::Env, PrefabWasmModule};
|
use crate::{
|
||||||
use crate::{CodeHash, CodeStorage, PristineCode, Schedule, Trait};
|
wasm::{prepare, runtime::Env, PrefabWasmModule},
|
||||||
use sp_std::prelude::*;
|
CodeHash, CodeStorage, PristineCode, Schedule, Trait,
|
||||||
use sp_runtime::traits::Hash;
|
};
|
||||||
use frame_support::StorageMap;
|
use frame_support::StorageMap;
|
||||||
|
use sp_runtime::traits::Hash;
|
||||||
|
use sp_std::prelude::*;
|
||||||
|
|
||||||
/// Put code in the storage. The hash of code is used as a key and is returned
|
/// Put code in the storage. The hash of code is used as a key and is returned
|
||||||
/// as a result of this function.
|
/// as a result of this function.
|
||||||
@@ -58,8 +60,7 @@ pub fn load<T: Trait>(
|
|||||||
code_hash: &CodeHash<T>,
|
code_hash: &CodeHash<T>,
|
||||||
schedule: &Schedule,
|
schedule: &Schedule,
|
||||||
) -> Result<PrefabWasmModule, &'static str> {
|
) -> Result<PrefabWasmModule, &'static str> {
|
||||||
let mut prefab_module =
|
let mut prefab_module = <CodeStorage<T>>::get(code_hash).ok_or_else(|| "code is not found")?;
|
||||||
<CodeStorage<T>>::get(code_hash).ok_or_else(|| "code is not found")?;
|
|
||||||
|
|
||||||
if prefab_module.schedule_version < schedule.version {
|
if prefab_module.schedule_version < schedule.version {
|
||||||
// The current schedule version is greater than the version of the one cached
|
// The current schedule version is greater than the version of the one cached
|
||||||
|
|||||||
@@ -193,14 +193,14 @@ macro_rules! define_env {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use parity_wasm::elements::FunctionType;
|
use crate::{
|
||||||
use parity_wasm::elements::ValueType;
|
exec::Ext,
|
||||||
|
gas::Gas,
|
||||||
|
wasm::{tests::MockExt, Runtime},
|
||||||
|
};
|
||||||
|
use parity_wasm::elements::{FunctionType, ValueType};
|
||||||
use sp_runtime::traits::Zero;
|
use sp_runtime::traits::Zero;
|
||||||
use sp_sandbox::{ReturnValue, Value};
|
use sp_sandbox::{ReturnValue, Value};
|
||||||
use crate::wasm::tests::MockExt;
|
|
||||||
use crate::wasm::Runtime;
|
|
||||||
use crate::exec::Ext;
|
|
||||||
use crate::gas::Gas;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn macro_unmarshall_then_body_then_marshall_value_or_trap() {
|
fn macro_unmarshall_then_body_then_marshall_value_or_trap() {
|
||||||
@@ -263,8 +263,10 @@ mod tests {
|
|||||||
Err(sp_sandbox::HostError)
|
Err(sp_sandbox::HostError)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let _f: fn(&mut Runtime<MockExt>, &[sp_sandbox::Value])
|
let _f: fn(
|
||||||
-> Result<sp_sandbox::ReturnValue, sp_sandbox::HostError> = ext_gas::<MockExt>;
|
&mut Runtime<MockExt>,
|
||||||
|
&[sp_sandbox::Value],
|
||||||
|
) -> Result<sp_sandbox::ReturnValue, sp_sandbox::HostError> = ext_gas::<MockExt>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -317,7 +319,13 @@ mod tests {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(Env::can_satisfy(b"ext_gas", &FunctionType::new(vec![ValueType::I32], None)));
|
assert!(Env::can_satisfy(
|
||||||
assert!(!Env::can_satisfy(b"not_exists", &FunctionType::new(vec![], None)));
|
b"ext_gas",
|
||||||
|
&FunctionType::new(vec![ValueType::I32], None)
|
||||||
|
));
|
||||||
|
assert!(!Env::can_satisfy(
|
||||||
|
b"not_exists",
|
||||||
|
&FunctionType::new(vec![], None)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@
|
|||||||
use super::Runtime;
|
use super::Runtime;
|
||||||
use crate::exec::Ext;
|
use crate::exec::Ext;
|
||||||
|
|
||||||
use sp_sandbox::Value;
|
|
||||||
use parity_wasm::elements::{FunctionType, ValueType};
|
use parity_wasm::elements::{FunctionType, ValueType};
|
||||||
|
use sp_sandbox::Value;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub(crate) mod macros;
|
pub(crate) mod macros;
|
||||||
@@ -66,10 +66,9 @@ impl ConvertibleToWasm for u64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type HostFunc<E> =
|
pub(crate) type HostFunc<E> = fn(
|
||||||
fn(
|
|
||||||
&mut Runtime<E>,
|
&mut Runtime<E>,
|
||||||
&[sp_sandbox::Value]
|
&[sp_sandbox::Value],
|
||||||
) -> Result<sp_sandbox::ReturnValue, sp_sandbox::HostError>;
|
) -> Result<sp_sandbox::ReturnValue, sp_sandbox::HostError>;
|
||||||
|
|
||||||
pub(crate) trait FunctionImplProvider<E: Ext> {
|
pub(crate) trait FunctionImplProvider<E: Ext> {
|
||||||
|
|||||||
@@ -17,14 +17,16 @@
|
|||||||
//! This module provides a means for executing contracts
|
//! This module provides a means for executing contracts
|
||||||
//! represented in wasm.
|
//! represented in wasm.
|
||||||
|
|
||||||
use crate::{CodeHash, Schedule, Trait};
|
use crate::{
|
||||||
use crate::wasm::env_def::FunctionImplProvider;
|
exec::{ExecResult, Ext},
|
||||||
use crate::exec::{Ext, ExecResult};
|
gas::GasMeter,
|
||||||
use crate::gas::GasMeter;
|
wasm::env_def::FunctionImplProvider,
|
||||||
|
CodeHash, Schedule, Trait,
|
||||||
|
};
|
||||||
|
|
||||||
use sp_std::prelude::*;
|
use codec::{Decode, Encode};
|
||||||
use codec::{Encode, Decode};
|
|
||||||
use sp_sandbox;
|
use sp_sandbox;
|
||||||
|
use sp_std::prelude::*;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod env_def;
|
mod env_def;
|
||||||
@@ -32,8 +34,10 @@ mod code_cache;
|
|||||||
mod prepare;
|
mod prepare;
|
||||||
mod runtime;
|
mod runtime;
|
||||||
|
|
||||||
use self::runtime::{to_execution_result, Runtime};
|
use self::{
|
||||||
use self::code_cache::load as load_code;
|
code_cache::load as load_code,
|
||||||
|
runtime::{to_execution_result, Runtime},
|
||||||
|
};
|
||||||
|
|
||||||
pub use self::code_cache::save as save_code;
|
pub use self::code_cache::save as save_code;
|
||||||
|
|
||||||
@@ -131,13 +135,7 @@ impl<'a, T: Trait> crate::exec::Vm<T> for WasmVm<'a> {
|
|||||||
imports.add_host_func("env", name, func_ptr);
|
imports.add_host_func("env", name, func_ptr);
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut runtime = Runtime::new(
|
let mut runtime = Runtime::new(&mut ext, input_data, &self.schedule, memory, gas_meter);
|
||||||
&mut ext,
|
|
||||||
input_data,
|
|
||||||
&self.schedule,
|
|
||||||
memory,
|
|
||||||
gas_meter,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Instantiate the instance from the instrumented module code and invoke the contract
|
// Instantiate the instance from the instrumented module code and invoke the contract
|
||||||
// entrypoint.
|
// entrypoint.
|
||||||
@@ -150,19 +148,20 @@ impl<'a, T: Trait> crate::exec::Vm<T> for WasmVm<'a> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::collections::HashMap;
|
use crate::{
|
||||||
use std::cell::RefCell;
|
exec::{ExecError, ExecReturnValue, Ext, StorageKey, STATUS_SUCCESS},
|
||||||
use sp_core::H256;
|
gas::{Gas, GasMeter},
|
||||||
use crate::exec::{Ext, StorageKey, ExecError, ExecReturnValue, STATUS_SUCCESS};
|
tests::{Call, Test},
|
||||||
use crate::gas::{Gas, GasMeter};
|
wasm::prepare::prepare_contract,
|
||||||
use crate::tests::{Test, Call};
|
BalanceOf, CodeHash,
|
||||||
use crate::wasm::prepare::prepare_contract;
|
};
|
||||||
use crate::{CodeHash, BalanceOf};
|
|
||||||
use wabt;
|
|
||||||
use hex_literal::hex;
|
|
||||||
use assert_matches::assert_matches;
|
use assert_matches::assert_matches;
|
||||||
use sp_runtime::DispatchError;
|
|
||||||
use frame_support::weights::Weight;
|
use frame_support::weights::Weight;
|
||||||
|
use hex_literal::hex;
|
||||||
|
use sp_core::H256;
|
||||||
|
use sp_runtime::DispatchError;
|
||||||
|
use std::{cell::RefCell, collections::HashMap};
|
||||||
|
use wabt;
|
||||||
|
|
||||||
const GAS_LIMIT: Gas = 10_000_000_000;
|
const GAS_LIMIT: Gas = 10_000_000_000;
|
||||||
|
|
||||||
@@ -230,9 +229,11 @@ mod tests {
|
|||||||
fn get_storage(&self, key: &StorageKey) -> Option<Vec<u8>> {
|
fn get_storage(&self, key: &StorageKey) -> Option<Vec<u8>> {
|
||||||
self.storage.get(key).cloned()
|
self.storage.get(key).cloned()
|
||||||
}
|
}
|
||||||
fn set_storage(&mut self, key: StorageKey, value: Option<Vec<u8>>)
|
fn set_storage(
|
||||||
-> Result<(), &'static str>
|
&mut self,
|
||||||
{
|
key: StorageKey,
|
||||||
|
value: Option<Vec<u8>>,
|
||||||
|
) -> Result<(), &'static str> {
|
||||||
*self.storage.entry(key).or_insert(Vec::new()) = value.unwrap_or(Vec::new());
|
*self.storage.entry(key).or_insert(Vec::new()) = value.unwrap_or(Vec::new());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -289,7 +290,10 @@ mod tests {
|
|||||||
});
|
});
|
||||||
// Assume for now that it was just a plain transfer.
|
// Assume for now that it was just a plain transfer.
|
||||||
// TODO: Add tests for different call outcomes.
|
// TODO: Add tests for different call outcomes.
|
||||||
Ok(ExecReturnValue { status: STATUS_SUCCESS, data: Vec::new() })
|
Ok(ExecReturnValue {
|
||||||
|
status: STATUS_SUCCESS,
|
||||||
|
data: Vec::new(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn terminate(
|
fn terminate(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -360,21 +364,22 @@ mod tests {
|
|||||||
self.rent_allowance
|
self.rent_allowance
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_number(&self) -> u64 { 121 }
|
fn block_number(&self) -> u64 {
|
||||||
|
121
|
||||||
|
}
|
||||||
|
|
||||||
fn max_value_size(&self) -> u32 { 16_384 }
|
fn max_value_size(&self) -> u32 {
|
||||||
|
16_384
|
||||||
|
}
|
||||||
|
|
||||||
fn get_runtime_storage(&self, key: &[u8]) -> Option<Vec<u8>> {
|
fn get_runtime_storage(&self, key: &[u8]) -> Option<Vec<u8>> {
|
||||||
let opt_value = self.runtime_storage_keys
|
let opt_value = self.runtime_storage_keys.borrow_mut().remove(key);
|
||||||
.borrow_mut()
|
opt_value.unwrap_or_else(|| {
|
||||||
.remove(key);
|
|
||||||
opt_value.unwrap_or_else(||
|
|
||||||
panic!(
|
panic!(
|
||||||
"{:?} doesn't exist. values that do exist {:?}",
|
"{:?} doesn't exist. values that do exist {:?}",
|
||||||
key,
|
key, self.runtime_storage_keys
|
||||||
self.runtime_storage_keys
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn get_weight_price(&self, weight: Weight) -> BalanceOf<Self::T> {
|
fn get_weight_price(&self, weight: Weight) -> BalanceOf<Self::T> {
|
||||||
BalanceOf::<Self::T>::from(1312_u32).saturating_mul(weight.into())
|
BalanceOf::<Self::T>::from(1312_u32).saturating_mul(weight.into())
|
||||||
@@ -387,9 +392,11 @@ mod tests {
|
|||||||
fn get_storage(&self, key: &[u8; 32]) -> Option<Vec<u8>> {
|
fn get_storage(&self, key: &[u8; 32]) -> Option<Vec<u8>> {
|
||||||
(**self).get_storage(key)
|
(**self).get_storage(key)
|
||||||
}
|
}
|
||||||
fn set_storage(&mut self, key: [u8; 32], value: Option<Vec<u8>>)
|
fn set_storage(
|
||||||
-> Result<(), &'static str>
|
&mut self,
|
||||||
{
|
key: [u8; 32],
|
||||||
|
value: Option<Vec<u8>>,
|
||||||
|
) -> Result<(), &'static str> {
|
||||||
(**self).set_storage(key, value)
|
(**self).set_storage(key, value)
|
||||||
}
|
}
|
||||||
fn instantiate(
|
fn instantiate(
|
||||||
@@ -435,12 +442,7 @@ mod tests {
|
|||||||
rent_allowance: u64,
|
rent_allowance: u64,
|
||||||
delta: Vec<StorageKey>,
|
delta: Vec<StorageKey>,
|
||||||
) {
|
) {
|
||||||
(**self).note_restore_to(
|
(**self).note_restore_to(dest, code_hash, rent_allowance, delta)
|
||||||
dest,
|
|
||||||
code_hash,
|
|
||||||
rent_allowance,
|
|
||||||
delta,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
fn caller(&self) -> &u64 {
|
fn caller(&self) -> &u64 {
|
||||||
(**self).caller()
|
(**self).caller()
|
||||||
@@ -499,8 +501,7 @@ mod tests {
|
|||||||
|
|
||||||
let wasm = wabt::wat2wasm(wat).unwrap();
|
let wasm = wabt::wat2wasm(wat).unwrap();
|
||||||
let schedule = crate::Schedule::default();
|
let schedule = crate::Schedule::default();
|
||||||
let prefab_module =
|
let prefab_module = prepare_contract::<super::runtime::Env>(&wasm, &schedule).unwrap();
|
||||||
prepare_contract::<super::runtime::Env>(&wasm, &schedule).unwrap();
|
|
||||||
|
|
||||||
let exec = WasmExecutable {
|
let exec = WasmExecutable {
|
||||||
// Use a "call" convention.
|
// Use a "call" convention.
|
||||||
@@ -554,7 +555,8 @@ mod tests {
|
|||||||
vec![],
|
vec![],
|
||||||
&mut mock_ext,
|
&mut mock_ext,
|
||||||
&mut GasMeter::new(GAS_LIMIT),
|
&mut GasMeter::new(GAS_LIMIT),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&mock_ext.transfers,
|
&mock_ext.transfers,
|
||||||
@@ -614,7 +616,8 @@ mod tests {
|
|||||||
vec![],
|
vec![],
|
||||||
&mut mock_ext,
|
&mut mock_ext,
|
||||||
&mut GasMeter::new(GAS_LIMIT),
|
&mut GasMeter::new(GAS_LIMIT),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&mock_ext.transfers,
|
&mock_ext.transfers,
|
||||||
@@ -676,7 +679,8 @@ mod tests {
|
|||||||
vec![],
|
vec![],
|
||||||
&mut mock_ext,
|
&mut mock_ext,
|
||||||
&mut GasMeter::new(GAS_LIMIT),
|
&mut GasMeter::new(GAS_LIMIT),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&mock_ext.instantiates,
|
&mock_ext.instantiates,
|
||||||
@@ -719,7 +723,8 @@ mod tests {
|
|||||||
vec![],
|
vec![],
|
||||||
&mut mock_ext,
|
&mut mock_ext,
|
||||||
&mut GasMeter::new(GAS_LIMIT),
|
&mut GasMeter::new(GAS_LIMIT),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&mock_ext.terminations,
|
&mock_ext.terminations,
|
||||||
@@ -777,7 +782,8 @@ mod tests {
|
|||||||
vec![],
|
vec![],
|
||||||
&mut mock_ext,
|
&mut mock_ext,
|
||||||
&mut GasMeter::new(GAS_LIMIT),
|
&mut GasMeter::new(GAS_LIMIT),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&mock_ext.transfers,
|
&mock_ext.transfers,
|
||||||
@@ -861,18 +867,23 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn get_storage_puts_data_into_scratch_buf() {
|
fn get_storage_puts_data_into_scratch_buf() {
|
||||||
let mut mock_ext = MockExt::default();
|
let mut mock_ext = MockExt::default();
|
||||||
mock_ext
|
mock_ext.storage.insert([0x11; 32], [0x22; 32].to_vec());
|
||||||
.storage
|
|
||||||
.insert([0x11; 32], [0x22; 32].to_vec());
|
|
||||||
|
|
||||||
let output = execute(
|
let output = execute(
|
||||||
CODE_GET_STORAGE,
|
CODE_GET_STORAGE,
|
||||||
vec![],
|
vec![],
|
||||||
mock_ext,
|
mock_ext,
|
||||||
&mut GasMeter::new(GAS_LIMIT),
|
&mut GasMeter::new(GAS_LIMIT),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(output, ExecReturnValue { status: STATUS_SUCCESS, data: [0x22; 32].to_vec() });
|
assert_eq!(
|
||||||
|
output,
|
||||||
|
ExecReturnValue {
|
||||||
|
status: STATUS_SUCCESS,
|
||||||
|
data: [0x22; 32].to_vec()
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// calls `ext_caller`, loads the address from the scratch buffer and
|
/// calls `ext_caller`, loads the address from the scratch buffer and
|
||||||
@@ -934,7 +945,8 @@ mod tests {
|
|||||||
vec![],
|
vec![],
|
||||||
MockExt::default(),
|
MockExt::default(),
|
||||||
&mut GasMeter::new(GAS_LIMIT),
|
&mut GasMeter::new(GAS_LIMIT),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// calls `ext_address`, loads the address from the scratch buffer and
|
/// calls `ext_address`, loads the address from the scratch buffer and
|
||||||
@@ -996,7 +1008,8 @@ mod tests {
|
|||||||
vec![],
|
vec![],
|
||||||
MockExt::default(),
|
MockExt::default(),
|
||||||
&mut GasMeter::new(GAS_LIMIT),
|
&mut GasMeter::new(GAS_LIMIT),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CODE_BALANCE: &str = r#"
|
const CODE_BALANCE: &str = r#"
|
||||||
@@ -1051,12 +1064,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn balance() {
|
fn balance() {
|
||||||
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
||||||
let _ = execute(
|
let _ = execute(CODE_BALANCE, vec![], MockExt::default(), &mut gas_meter).unwrap();
|
||||||
CODE_BALANCE,
|
|
||||||
vec![],
|
|
||||||
MockExt::default(),
|
|
||||||
&mut gas_meter,
|
|
||||||
).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const CODE_GAS_PRICE: &str = r#"
|
const CODE_GAS_PRICE: &str = r#"
|
||||||
@@ -1111,12 +1119,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn gas_price() {
|
fn gas_price() {
|
||||||
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
||||||
let _ = execute(
|
let _ = execute(CODE_GAS_PRICE, vec![], MockExt::default(), &mut gas_meter).unwrap();
|
||||||
CODE_GAS_PRICE,
|
|
||||||
vec![],
|
|
||||||
MockExt::default(),
|
|
||||||
&mut gas_meter,
|
|
||||||
).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const CODE_GAS_LEFT: &str = r#"
|
const CODE_GAS_LEFT: &str = r#"
|
||||||
@@ -1170,16 +1173,14 @@ mod tests {
|
|||||||
fn gas_left() {
|
fn gas_left() {
|
||||||
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
||||||
|
|
||||||
let output = execute(
|
let output = execute(CODE_GAS_LEFT, vec![], MockExt::default(), &mut gas_meter).unwrap();
|
||||||
CODE_GAS_LEFT,
|
|
||||||
vec![],
|
|
||||||
MockExt::default(),
|
|
||||||
&mut gas_meter,
|
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
let gas_left = Gas::decode(&mut output.data.as_slice()).unwrap();
|
let gas_left = Gas::decode(&mut output.data.as_slice()).unwrap();
|
||||||
assert!(gas_left < GAS_LIMIT, "gas_left must be less than initial");
|
assert!(gas_left < GAS_LIMIT, "gas_left must be less than initial");
|
||||||
assert!(gas_left > gas_meter.gas_left(), "gas_left must be greater than final");
|
assert!(
|
||||||
|
gas_left > gas_meter.gas_left(),
|
||||||
|
"gas_left must be greater than final"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const CODE_VALUE_TRANSFERRED: &str = r#"
|
const CODE_VALUE_TRANSFERRED: &str = r#"
|
||||||
@@ -1239,7 +1240,8 @@ mod tests {
|
|||||||
vec![],
|
vec![],
|
||||||
MockExt::default(),
|
MockExt::default(),
|
||||||
&mut gas_meter,
|
&mut gas_meter,
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CODE_DISPATCH_CALL: &str = r#"
|
const CODE_DISPATCH_CALL: &str = r#"
|
||||||
@@ -1270,13 +1272,14 @@ mod tests {
|
|||||||
vec![],
|
vec![],
|
||||||
&mut mock_ext,
|
&mut mock_ext,
|
||||||
&mut GasMeter::new(GAS_LIMIT),
|
&mut GasMeter::new(GAS_LIMIT),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&mock_ext.dispatches,
|
&mock_ext.dispatches,
|
||||||
&[DispatchEntry(
|
&[DispatchEntry(Call::Balances(
|
||||||
Call::Balances(pallet_balances::Call::set_balance(42, 1337, 0)),
|
pallet_balances::Call::set_balance(42, 1337, 0)
|
||||||
)]
|
),)]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1310,9 +1313,16 @@ mod tests {
|
|||||||
vec![],
|
vec![],
|
||||||
MockExt::default(),
|
MockExt::default(),
|
||||||
&mut GasMeter::new(GAS_LIMIT),
|
&mut GasMeter::new(GAS_LIMIT),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(output, ExecReturnValue { status: STATUS_SUCCESS, data: vec![1, 2, 3, 4] });
|
assert_eq!(
|
||||||
|
output,
|
||||||
|
ExecReturnValue {
|
||||||
|
status: STATUS_SUCCESS,
|
||||||
|
data: vec![1, 2, 3, 4]
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const CODE_TIMESTAMP_NOW: &str = r#"
|
const CODE_TIMESTAMP_NOW: &str = r#"
|
||||||
@@ -1372,7 +1382,8 @@ mod tests {
|
|||||||
vec![],
|
vec![],
|
||||||
MockExt::default(),
|
MockExt::default(),
|
||||||
&mut gas_meter,
|
&mut gas_meter,
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CODE_MINIMUM_BALANCE: &str = r#"
|
const CODE_MINIMUM_BALANCE: &str = r#"
|
||||||
@@ -1431,7 +1442,8 @@ mod tests {
|
|||||||
vec![],
|
vec![],
|
||||||
MockExt::default(),
|
MockExt::default(),
|
||||||
&mut gas_meter,
|
&mut gas_meter,
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CODE_TOMBSTONE_DEPOSIT: &str = r#"
|
const CODE_TOMBSTONE_DEPOSIT: &str = r#"
|
||||||
@@ -1490,7 +1502,8 @@ mod tests {
|
|||||||
vec![],
|
vec![],
|
||||||
MockExt::default(),
|
MockExt::default(),
|
||||||
&mut gas_meter,
|
&mut gas_meter,
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CODE_RANDOM: &str = r#"
|
const CODE_RANDOM: &str = r#"
|
||||||
@@ -1554,19 +1567,15 @@ mod tests {
|
|||||||
fn random() {
|
fn random() {
|
||||||
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
||||||
|
|
||||||
let output = execute(
|
let output = execute(CODE_RANDOM, vec![], MockExt::default(), &mut gas_meter).unwrap();
|
||||||
CODE_RANDOM,
|
|
||||||
vec![],
|
|
||||||
MockExt::default(),
|
|
||||||
&mut gas_meter,
|
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
// The mock ext just returns the same data that was passed as the subject.
|
// The mock ext just returns the same data that was passed as the subject.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
output,
|
output,
|
||||||
ExecReturnValue {
|
ExecReturnValue {
|
||||||
status: STATUS_SUCCESS,
|
status: STATUS_SUCCESS,
|
||||||
data: hex!("000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F").to_vec(),
|
data: hex!("000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F")
|
||||||
|
.to_vec(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1598,17 +1607,15 @@ mod tests {
|
|||||||
fn deposit_event() {
|
fn deposit_event() {
|
||||||
let mut mock_ext = MockExt::default();
|
let mut mock_ext = MockExt::default();
|
||||||
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
||||||
let _ = execute(
|
let _ = execute(CODE_DEPOSIT_EVENT, vec![], &mut mock_ext, &mut gas_meter).unwrap();
|
||||||
CODE_DEPOSIT_EVENT,
|
|
||||||
vec![],
|
|
||||||
&mut mock_ext,
|
|
||||||
&mut gas_meter
|
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(mock_ext.events, vec![
|
assert_eq!(
|
||||||
(vec![H256::repeat_byte(0x33)],
|
mock_ext.events,
|
||||||
vec![0x00, 0x01, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x14, 0x00])
|
vec![(
|
||||||
]);
|
vec![H256::repeat_byte(0x33)],
|
||||||
|
vec![0x00, 0x01, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x14, 0x00]
|
||||||
|
)]
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(gas_meter.gas_left(), 9967000000);
|
assert_eq!(gas_meter.gas_left(), 9967000000);
|
||||||
}
|
}
|
||||||
@@ -1653,7 +1660,8 @@ mod tests {
|
|||||||
&mut gas_meter
|
&mut gas_meter
|
||||||
),
|
),
|
||||||
Err(ExecError {
|
Err(ExecError {
|
||||||
reason: DispatchError::Other("contract trapped during execution"), buffer: _
|
reason: DispatchError::Other("contract trapped during execution"),
|
||||||
|
buffer: _,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1696,7 +1704,10 @@ mod tests {
|
|||||||
MockExt::default(),
|
MockExt::default(),
|
||||||
&mut gas_meter
|
&mut gas_meter
|
||||||
),
|
),
|
||||||
Err(ExecError { reason: DispatchError::Other("contract trapped during execution"), buffer: _ })
|
Err(ExecError {
|
||||||
|
reason: DispatchError::Other("contract trapped during execution"),
|
||||||
|
buffer: _,
|
||||||
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1759,7 +1770,8 @@ mod tests {
|
|||||||
vec![],
|
vec![],
|
||||||
MockExt::default(),
|
MockExt::default(),
|
||||||
&mut GasMeter::new(GAS_LIMIT),
|
&mut GasMeter::new(GAS_LIMIT),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// asserts that the size of the input data is 4.
|
// asserts that the size of the input data is 4.
|
||||||
@@ -1799,7 +1811,8 @@ mod tests {
|
|||||||
input_data,
|
input_data,
|
||||||
MockExt::default(),
|
MockExt::default(),
|
||||||
&mut GasMeter::new(GAS_LIMIT),
|
&mut GasMeter::new(GAS_LIMIT),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(output.data.len(), 0);
|
assert_eq!(output.data.len(), 0);
|
||||||
assert_eq!(output.data.capacity(), 1_234);
|
assert_eq!(output.data.capacity(), 1_234);
|
||||||
@@ -1815,7 +1828,9 @@ mod tests {
|
|||||||
input_data,
|
input_data,
|
||||||
MockExt::default(),
|
MockExt::default(),
|
||||||
&mut GasMeter::new(GAS_LIMIT),
|
&mut GasMeter::new(GAS_LIMIT),
|
||||||
).err().unwrap();
|
)
|
||||||
|
.err()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(error.buffer.capacity(), 1_234);
|
assert_eq!(error.buffer.capacity(), 1_234);
|
||||||
}
|
}
|
||||||
@@ -1869,9 +1884,16 @@ mod tests {
|
|||||||
hex!("00112233445566778899").to_vec(),
|
hex!("00112233445566778899").to_vec(),
|
||||||
MockExt::default(),
|
MockExt::default(),
|
||||||
&mut GasMeter::new(GAS_LIMIT),
|
&mut GasMeter::new(GAS_LIMIT),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(output, ExecReturnValue { status: 0, data: hex!("445566778899").to_vec() });
|
assert_eq!(
|
||||||
|
output,
|
||||||
|
ExecReturnValue {
|
||||||
|
status: 0,
|
||||||
|
data: hex!("445566778899").to_vec()
|
||||||
|
}
|
||||||
|
);
|
||||||
assert!(output.is_success());
|
assert!(output.is_success());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1882,9 +1904,16 @@ mod tests {
|
|||||||
hex!("112233445566778899").to_vec(),
|
hex!("112233445566778899").to_vec(),
|
||||||
MockExt::default(),
|
MockExt::default(),
|
||||||
&mut GasMeter::new(GAS_LIMIT),
|
&mut GasMeter::new(GAS_LIMIT),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(output, ExecReturnValue { status: 17, data: hex!("5566778899").to_vec() });
|
assert_eq!(
|
||||||
|
output,
|
||||||
|
ExecReturnValue {
|
||||||
|
status: 17,
|
||||||
|
data: hex!("5566778899").to_vec()
|
||||||
|
}
|
||||||
|
);
|
||||||
assert!(!output.is_success());
|
assert!(!output.is_success());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1973,17 +2002,15 @@ mod tests {
|
|||||||
// "\01\02\03\04" - Some(0x14144020)
|
// "\01\02\03\04" - Some(0x14144020)
|
||||||
// "\02\03\04\05" - None
|
// "\02\03\04\05" - None
|
||||||
*mock_ext.runtime_storage_keys.borrow_mut() = [
|
*mock_ext.runtime_storage_keys.borrow_mut() = [
|
||||||
([1, 2, 3, 4].to_vec(), Some(0x14144020u32.to_le_bytes().to_vec())),
|
(
|
||||||
|
[1, 2, 3, 4].to_vec(),
|
||||||
|
Some(0x14144020u32.to_le_bytes().to_vec()),
|
||||||
|
),
|
||||||
([2, 3, 4, 5].to_vec().to_vec(), None),
|
([2, 3, 4, 5].to_vec().to_vec(), None),
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
let _ = execute(
|
let _ = execute(CODE_GET_RUNTIME_STORAGE, vec![], mock_ext, &mut gas_meter).unwrap();
|
||||||
CODE_GET_RUNTIME_STORAGE,
|
|
||||||
vec![],
|
|
||||||
mock_ext,
|
|
||||||
&mut gas_meter,
|
|
||||||
).unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,15 +18,15 @@
|
|||||||
//! wasm module before execution. It also extracts some essential information
|
//! wasm module before execution. It also extracts some essential information
|
||||||
//! from a module.
|
//! from a module.
|
||||||
|
|
||||||
use crate::wasm::env_def::ImportSatisfyCheck;
|
use crate::{
|
||||||
use crate::wasm::PrefabWasmModule;
|
wasm::{env_def::ImportSatisfyCheck, PrefabWasmModule},
|
||||||
use crate::Schedule;
|
Schedule,
|
||||||
|
};
|
||||||
|
|
||||||
use parity_wasm::elements::{self, Internal, External, MemoryType, Type, ValueType};
|
use parity_wasm::elements::{self, External, Internal, MemoryType, Type, ValueType};
|
||||||
use pwasm_utils;
|
use pwasm_utils::{self, rules};
|
||||||
use pwasm_utils::rules;
|
use sp_runtime::traits::SaturatedConversion;
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
use sp_runtime::traits::{SaturatedConversion};
|
|
||||||
|
|
||||||
struct ContractModule<'a> {
|
struct ContractModule<'a> {
|
||||||
/// A deserialized module. The module is valid (this is Guaranteed by `new` method).
|
/// A deserialized module. The module is valid (this is Guaranteed by `new` method).
|
||||||
@@ -39,10 +39,7 @@ impl<'a> ContractModule<'a> {
|
|||||||
///
|
///
|
||||||
/// Returns `Err` if the `original_code` couldn't be decoded or
|
/// Returns `Err` if the `original_code` couldn't be decoded or
|
||||||
/// if it contains an invalid module.
|
/// if it contains an invalid module.
|
||||||
fn new(
|
fn new(original_code: &[u8], schedule: &'a Schedule) -> Result<Self, &'static str> {
|
||||||
original_code: &[u8],
|
|
||||||
schedule: &'a Schedule,
|
|
||||||
) -> Result<Self, &'static str> {
|
|
||||||
use wasmi_validation::{validate_module, PlainValidator};
|
use wasmi_validation::{validate_module, PlainValidator};
|
||||||
|
|
||||||
let module =
|
let module =
|
||||||
@@ -53,10 +50,7 @@ impl<'a> ContractModule<'a> {
|
|||||||
|
|
||||||
// Return a `ContractModule` instance with
|
// Return a `ContractModule` instance with
|
||||||
// __valid__ module.
|
// __valid__ module.
|
||||||
Ok(ContractModule {
|
Ok(ContractModule { module, schedule })
|
||||||
module,
|
|
||||||
schedule,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensures that module doesn't declare internal memories.
|
/// Ensures that module doesn't declare internal memories.
|
||||||
@@ -65,7 +59,8 @@ impl<'a> ContractModule<'a> {
|
|||||||
/// Memory section contains declarations of internal linear memories, so if we find one
|
/// Memory section contains declarations of internal linear memories, so if we find one
|
||||||
/// we reject such a module.
|
/// we reject such a module.
|
||||||
fn ensure_no_internal_memory(&self) -> Result<(), &'static str> {
|
fn ensure_no_internal_memory(&self) -> Result<(), &'static str> {
|
||||||
if self.module
|
if self
|
||||||
|
.module
|
||||||
.memory_section()
|
.memory_section()
|
||||||
.map_or(false, |ms| ms.entries().len() > 0)
|
.map_or(false, |ms| ms.entries().len() > 0)
|
||||||
{
|
{
|
||||||
@@ -86,7 +81,7 @@ impl<'a> ContractModule<'a> {
|
|||||||
// Check the table's initial size as there is no instruction or environment function
|
// Check the table's initial size as there is no instruction or environment function
|
||||||
// capable of growing the table.
|
// capable of growing the table.
|
||||||
if table_type.limits().initial() > limit {
|
if table_type.limits().initial() > limit {
|
||||||
return Err("table exceeds maximum size allowed")
|
return Err("table exceeds maximum size allowed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,8 +93,9 @@ impl<'a> ContractModule<'a> {
|
|||||||
if let Some(global_section) = self.module.global_section() {
|
if let Some(global_section) = self.module.global_section() {
|
||||||
for global in global_section.entries() {
|
for global in global_section.entries() {
|
||||||
match global.global_type().content_type() {
|
match global.global_type().content_type() {
|
||||||
ValueType::F32 | ValueType::F64 =>
|
ValueType::F32 | ValueType::F64 => {
|
||||||
return Err("use of floating point type in globals is forbidden"),
|
return Err("use of floating point type in globals is forbidden")
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,8 +105,9 @@ impl<'a> ContractModule<'a> {
|
|||||||
for func_body in code_section.bodies() {
|
for func_body in code_section.bodies() {
|
||||||
for local in func_body.locals() {
|
for local in func_body.locals() {
|
||||||
match local.value_type() {
|
match local.value_type() {
|
||||||
ValueType::F32 | ValueType::F64 =>
|
ValueType::F32 | ValueType::F64 => {
|
||||||
return Err("use of floating point type in locals is forbidden"),
|
return Err("use of floating point type in locals is forbidden")
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,8 +121,11 @@ impl<'a> ContractModule<'a> {
|
|||||||
let return_type = func_type.return_type();
|
let return_type = func_type.return_type();
|
||||||
for value_type in func_type.params().iter().chain(return_type.iter()) {
|
for value_type in func_type.params().iter().chain(return_type.iter()) {
|
||||||
match value_type {
|
match value_type {
|
||||||
ValueType::F32 | ValueType::F64 =>
|
ValueType::F32 | ValueType::F64 => {
|
||||||
return Err("use of floating point type in function types is forbidden"),
|
return Err(
|
||||||
|
"use of floating point type in function types is forbidden",
|
||||||
|
)
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,8 +138,7 @@ impl<'a> ContractModule<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn inject_gas_metering(self) -> Result<Self, &'static str> {
|
fn inject_gas_metering(self) -> Result<Self, &'static str> {
|
||||||
let gas_rules =
|
let gas_rules = rules::Set::new(
|
||||||
rules::Set::new(
|
|
||||||
self.schedule.regular_op_cost.clone().saturated_into(),
|
self.schedule.regular_op_cost.clone().saturated_into(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
)
|
)
|
||||||
@@ -195,11 +194,9 @@ impl<'a> ContractModule<'a> {
|
|||||||
.map(|is| is.entries())
|
.map(|is| is.entries())
|
||||||
.unwrap_or(&[])
|
.unwrap_or(&[])
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|entry| {
|
.filter(|entry| match *entry.external() {
|
||||||
match *entry.external() {
|
|
||||||
External::Function(_) => true,
|
External::Function(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
@@ -232,15 +229,17 @@ impl<'a> ContractModule<'a> {
|
|||||||
// The [] -> [] signature predates the [] -> [i32] signature and is supported for
|
// The [] -> [] signature predates the [] -> [i32] signature and is supported for
|
||||||
// backwards compatibility. This will likely be removed once ink! is updated to
|
// backwards compatibility. This will likely be removed once ink! is updated to
|
||||||
// generate modules with the new function signatures.
|
// generate modules with the new function signatures.
|
||||||
let func_ty_idx = func_entries.get(fn_idx as usize)
|
let func_ty_idx = func_entries
|
||||||
|
.get(fn_idx as usize)
|
||||||
.ok_or_else(|| "export refers to non-existent function")?
|
.ok_or_else(|| "export refers to non-existent function")?
|
||||||
.type_ref();
|
.type_ref();
|
||||||
let Type::Function(ref func_ty) = types
|
let Type::Function(ref func_ty) = types
|
||||||
.get(func_ty_idx as usize)
|
.get(func_ty_idx as usize)
|
||||||
.ok_or_else(|| "function has a non-existent type")?;
|
.ok_or_else(|| "function has a non-existent type")?;
|
||||||
if !func_ty.params().is_empty() ||
|
if !func_ty.params().is_empty()
|
||||||
!(func_ty.return_type().is_none() ||
|
|| !(func_ty.return_type().is_none()
|
||||||
func_ty.return_type() == Some(ValueType::I32)) {
|
|| func_ty.return_type() == Some(ValueType::I32))
|
||||||
|
{
|
||||||
return Err("entry point has wrong signature");
|
return Err("entry point has wrong signature");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,10 +285,10 @@ impl<'a> ContractModule<'a> {
|
|||||||
&External::Function(ref type_idx) => type_idx,
|
&External::Function(ref type_idx) => type_idx,
|
||||||
&External::Memory(ref memory_type) => {
|
&External::Memory(ref memory_type) => {
|
||||||
if import.field() != "memory" {
|
if import.field() != "memory" {
|
||||||
return Err("Memory import must have the field name 'memory'")
|
return Err("Memory import must have the field name 'memory'");
|
||||||
}
|
}
|
||||||
if imported_mem_type.is_some() {
|
if imported_mem_type.is_some() {
|
||||||
return Err("Multiple memory imports defined")
|
return Err("Multiple memory imports defined");
|
||||||
}
|
}
|
||||||
imported_mem_type = Some(memory_type);
|
imported_mem_type = Some(memory_type);
|
||||||
continue;
|
continue;
|
||||||
@@ -317,8 +316,7 @@ impl<'a> ContractModule<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn into_wasm_code(self) -> Result<Vec<u8>, &'static str> {
|
fn into_wasm_code(self) -> Result<Vec<u8>, &'static str> {
|
||||||
elements::serialize(self.module)
|
elements::serialize(self.module).map_err(|_| "error serializing instrumented module")
|
||||||
.map_err(|_| "error serializing instrumented module")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,9 +392,9 @@ pub fn prepare_contract<C: ImportSatisfyCheck>(
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::exec::Ext;
|
use crate::exec::Ext;
|
||||||
|
use assert_matches::assert_matches;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use wabt;
|
use wabt;
|
||||||
use assert_matches::assert_matches;
|
|
||||||
|
|
||||||
impl fmt::Debug for PrefabWasmModule {
|
impl fmt::Debug for PrefabWasmModule {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
@@ -429,7 +427,8 @@ mod tests {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare_test!(no_floats,
|
prepare_test!(
|
||||||
|
no_floats,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(func (export "call")
|
(func (export "call")
|
||||||
@@ -454,7 +453,8 @@ mod tests {
|
|||||||
assert_eq!(Schedule::default().max_memory_pages, 16);
|
assert_eq!(Schedule::default().max_memory_pages, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare_test!(memory_with_one_page,
|
prepare_test!(
|
||||||
|
memory_with_one_page,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "env" "memory" (memory 1 1))
|
(import "env" "memory" (memory 1 1))
|
||||||
@@ -466,7 +466,8 @@ mod tests {
|
|||||||
Ok(_)
|
Ok(_)
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(internal_memory_declaration,
|
prepare_test!(
|
||||||
|
internal_memory_declaration,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(memory 1 1)
|
(memory 1 1)
|
||||||
@@ -478,7 +479,8 @@ mod tests {
|
|||||||
Err("module declares internal memory")
|
Err("module declares internal memory")
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(no_memory_import,
|
prepare_test!(
|
||||||
|
no_memory_import,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
;; no memory imported
|
;; no memory imported
|
||||||
@@ -489,7 +491,8 @@ mod tests {
|
|||||||
Ok(_)
|
Ok(_)
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(initial_exceeds_maximum,
|
prepare_test!(
|
||||||
|
initial_exceeds_maximum,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "env" "memory" (memory 16 1))
|
(import "env" "memory" (memory 16 1))
|
||||||
@@ -501,7 +504,8 @@ mod tests {
|
|||||||
Err("Module is not valid")
|
Err("Module is not valid")
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(no_maximum,
|
prepare_test!(
|
||||||
|
no_maximum,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "env" "memory" (memory 1))
|
(import "env" "memory" (memory 1))
|
||||||
@@ -513,7 +517,8 @@ mod tests {
|
|||||||
Err("Maximum number of pages should be always declared.")
|
Err("Maximum number of pages should be always declared.")
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(requested_maximum_exceeds_configured_maximum,
|
prepare_test!(
|
||||||
|
requested_maximum_exceeds_configured_maximum,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "env" "memory" (memory 1 17))
|
(import "env" "memory" (memory 1 17))
|
||||||
@@ -525,7 +530,8 @@ mod tests {
|
|||||||
Err("Maximum number of pages should not exceed the configured maximum.")
|
Err("Maximum number of pages should not exceed the configured maximum.")
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(field_name_not_memory,
|
prepare_test!(
|
||||||
|
field_name_not_memory,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "env" "forgetit" (memory 1 1))
|
(import "env" "forgetit" (memory 1 1))
|
||||||
@@ -537,7 +543,8 @@ mod tests {
|
|||||||
Err("Memory import must have the field name 'memory'")
|
Err("Memory import must have the field name 'memory'")
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(multiple_memory_imports,
|
prepare_test!(
|
||||||
|
multiple_memory_imports,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "env" "memory" (memory 1 1))
|
(import "env" "memory" (memory 1 1))
|
||||||
@@ -550,7 +557,8 @@ mod tests {
|
|||||||
Err("Module is not valid")
|
Err("Module is not valid")
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(table_import,
|
prepare_test!(
|
||||||
|
table_import,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "env" "table" (table 1 anyfunc))
|
(import "env" "table" (table 1 anyfunc))
|
||||||
@@ -562,7 +570,8 @@ mod tests {
|
|||||||
Err("Cannot import tables")
|
Err("Cannot import tables")
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(global_import,
|
prepare_test!(
|
||||||
|
global_import,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(global $g (import "env" "global") i32)
|
(global $g (import "env" "global") i32)
|
||||||
@@ -583,7 +592,8 @@ mod tests {
|
|||||||
assert_eq!(Schedule::default().max_table_size, 16384);
|
assert_eq!(Schedule::default().max_table_size, 16384);
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare_test!(no_tables,
|
prepare_test!(
|
||||||
|
no_tables,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(func (export "call"))
|
(func (export "call"))
|
||||||
@@ -593,7 +603,8 @@ mod tests {
|
|||||||
Ok(_)
|
Ok(_)
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(table_valid_size,
|
prepare_test!(
|
||||||
|
table_valid_size,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(table 10000 funcref)
|
(table 10000 funcref)
|
||||||
@@ -605,7 +616,8 @@ mod tests {
|
|||||||
Ok(_)
|
Ok(_)
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(table_too_big,
|
prepare_test!(
|
||||||
|
table_too_big,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(table 20000 funcref)
|
(table 20000 funcref)
|
||||||
@@ -620,7 +632,8 @@ mod tests {
|
|||||||
mod imports {
|
mod imports {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
prepare_test!(can_import_legit_function,
|
prepare_test!(
|
||||||
|
can_import_legit_function,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "env" "nop" (func (param i64)))
|
(import "env" "nop" (func (param i64)))
|
||||||
@@ -634,7 +647,8 @@ mod tests {
|
|||||||
|
|
||||||
// even though gas is defined the contract can't import it since
|
// even though gas is defined the contract can't import it since
|
||||||
// it is an implementation defined.
|
// it is an implementation defined.
|
||||||
prepare_test!(can_not_import_gas_function,
|
prepare_test!(
|
||||||
|
can_not_import_gas_function,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "env" "gas" (func (param i32)))
|
(import "env" "gas" (func (param i32)))
|
||||||
@@ -647,7 +661,8 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// nothing can be imported from non-"env" module for now.
|
// nothing can be imported from non-"env" module for now.
|
||||||
prepare_test!(non_env_import,
|
prepare_test!(
|
||||||
|
non_env_import,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "another_module" "memory" (memory 1 1))
|
(import "another_module" "memory" (memory 1 1))
|
||||||
@@ -660,7 +675,8 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// wrong signature
|
// wrong signature
|
||||||
prepare_test!(wrong_signature,
|
prepare_test!(
|
||||||
|
wrong_signature,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "env" "gas" (func (param i64)))
|
(import "env" "gas" (func (param i64)))
|
||||||
@@ -672,7 +688,8 @@ mod tests {
|
|||||||
Err("module imports a non-existent function")
|
Err("module imports a non-existent function")
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(unknown_func_name,
|
prepare_test!(
|
||||||
|
unknown_func_name,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "env" "unknown_func" (func))
|
(import "env" "unknown_func" (func))
|
||||||
@@ -684,7 +701,8 @@ mod tests {
|
|||||||
Err("module imports a non-existent function")
|
Err("module imports a non-existent function")
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(ext_println_debug_disabled,
|
prepare_test!(
|
||||||
|
ext_println_debug_disabled,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "env" "ext_println" (func $ext_println (param i32 i32)))
|
(import "env" "ext_println" (func $ext_println (param i32 i32)))
|
||||||
@@ -698,7 +716,9 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ext_println_debug_enabled() {
|
fn ext_println_debug_enabled() {
|
||||||
let wasm = wabt::Wat2Wasm::new().validate(false).convert(
|
let wasm = wabt::Wat2Wasm::new()
|
||||||
|
.validate(false)
|
||||||
|
.convert(
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "env" "ext_println" (func $ext_println (param i32 i32)))
|
(import "env" "ext_println" (func $ext_println (param i32 i32)))
|
||||||
@@ -706,8 +726,9 @@ mod tests {
|
|||||||
(func (export "call"))
|
(func (export "call"))
|
||||||
(func (export "deploy"))
|
(func (export "deploy"))
|
||||||
)
|
)
|
||||||
"#
|
"#,
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
let mut schedule = Schedule::default();
|
let mut schedule = Schedule::default();
|
||||||
schedule.enable_println = true;
|
schedule.enable_println = true;
|
||||||
let r = prepare_contract::<TestEnv>(wasm.as_ref(), &schedule);
|
let r = prepare_contract::<TestEnv>(wasm.as_ref(), &schedule);
|
||||||
@@ -718,7 +739,8 @@ mod tests {
|
|||||||
mod entrypoints {
|
mod entrypoints {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
prepare_test!(it_works,
|
prepare_test!(
|
||||||
|
it_works,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(func (export "call"))
|
(func (export "call"))
|
||||||
@@ -728,7 +750,8 @@ mod tests {
|
|||||||
Ok(_)
|
Ok(_)
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(omit_deploy,
|
prepare_test!(
|
||||||
|
omit_deploy,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(func (export "call"))
|
(func (export "call"))
|
||||||
@@ -737,7 +760,8 @@ mod tests {
|
|||||||
Err("deploy function isn't exported")
|
Err("deploy function isn't exported")
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(omit_call,
|
prepare_test!(
|
||||||
|
omit_call,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(func (export "deploy"))
|
(func (export "deploy"))
|
||||||
@@ -747,7 +771,8 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Try to use imported function as an entry point.
|
// Try to use imported function as an entry point.
|
||||||
prepare_test!(try_sneak_export_as_entrypoint,
|
prepare_test!(
|
||||||
|
try_sneak_export_as_entrypoint,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "env" "panic" (func))
|
(import "env" "panic" (func))
|
||||||
@@ -761,7 +786,8 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Try to use imported function as an entry point.
|
// Try to use imported function as an entry point.
|
||||||
prepare_test!(try_sneak_export_as_global,
|
prepare_test!(
|
||||||
|
try_sneak_export_as_global,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(func (export "deploy"))
|
(func (export "deploy"))
|
||||||
@@ -771,7 +797,8 @@ mod tests {
|
|||||||
Err("expected a function")
|
Err("expected a function")
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(wrong_signature,
|
prepare_test!(
|
||||||
|
wrong_signature,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(func (export "deploy"))
|
(func (export "deploy"))
|
||||||
@@ -781,7 +808,8 @@ mod tests {
|
|||||||
Err("entry point has wrong signature")
|
Err("entry point has wrong signature")
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(unknown_exports,
|
prepare_test!(
|
||||||
|
unknown_exports,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(func (export "call"))
|
(func (export "call"))
|
||||||
@@ -792,7 +820,8 @@ mod tests {
|
|||||||
Err("unknown export: expecting only deploy and call functions")
|
Err("unknown export: expecting only deploy and call functions")
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(global_float,
|
prepare_test!(
|
||||||
|
global_float,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(global $x f32 (f32.const 0))
|
(global $x f32 (f32.const 0))
|
||||||
@@ -803,7 +832,8 @@ mod tests {
|
|||||||
Err("use of floating point type in globals is forbidden")
|
Err("use of floating point type in globals is forbidden")
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(local_float,
|
prepare_test!(
|
||||||
|
local_float,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(func $foo (local f32))
|
(func $foo (local f32))
|
||||||
@@ -814,7 +844,8 @@ mod tests {
|
|||||||
Err("use of floating point type in locals is forbidden")
|
Err("use of floating point type in locals is forbidden")
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(param_float,
|
prepare_test!(
|
||||||
|
param_float,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(func $foo (param f32))
|
(func $foo (param f32))
|
||||||
@@ -825,7 +856,8 @@ mod tests {
|
|||||||
Err("use of floating point type in function types is forbidden")
|
Err("use of floating point type in function types is forbidden")
|
||||||
);
|
);
|
||||||
|
|
||||||
prepare_test!(result_float,
|
prepare_test!(
|
||||||
|
result_float,
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(func $foo (result f32) (f32.const 0))
|
(func $foo (result f32) (f32.const 0))
|
||||||
|
|||||||
@@ -16,23 +16,18 @@
|
|||||||
|
|
||||||
//! Environment definition of the wasm smart-contract runtime.
|
//! Environment definition of the wasm smart-contract runtime.
|
||||||
|
|
||||||
use crate::{Schedule, Trait, CodeHash, BalanceOf};
|
use crate::{
|
||||||
use crate::exec::{
|
exec::{ExecError, ExecResult, ExecReturnValue, Ext, StorageKey, TopicOf, STATUS_SUCCESS},
|
||||||
Ext, ExecResult, ExecError, ExecReturnValue, StorageKey, TopicOf, STATUS_SUCCESS,
|
gas::{Gas, GasMeter, GasMeterResult, Token},
|
||||||
|
BalanceOf, CodeHash, Schedule, Trait,
|
||||||
};
|
};
|
||||||
use crate::gas::{Gas, GasMeter, Token, GasMeterResult};
|
|
||||||
use sp_sandbox;
|
|
||||||
use frame_system;
|
|
||||||
use sp_std::{prelude::*, mem, convert::TryInto};
|
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use sp_runtime::traits::{Bounded, SaturatedConversion};
|
|
||||||
use sp_io::hashing::{
|
|
||||||
keccak_256,
|
|
||||||
blake2_256,
|
|
||||||
blake2_128,
|
|
||||||
sha2_256,
|
|
||||||
};
|
|
||||||
use frame_support::weights::GetDispatchInfo;
|
use frame_support::weights::GetDispatchInfo;
|
||||||
|
use frame_system;
|
||||||
|
use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256};
|
||||||
|
use sp_runtime::traits::{Bounded, SaturatedConversion};
|
||||||
|
use sp_sandbox;
|
||||||
|
use sp_std::{convert::TryInto, mem, prelude::*};
|
||||||
|
|
||||||
/// The value returned from ext_call and ext_instantiate contract external functions if the call or
|
/// The value returned from ext_call and ext_instantiate contract external functions if the call or
|
||||||
/// instantiation traps. This value is chosen as if the execution does not trap, the return value
|
/// instantiation traps. This value is chosen as if the execution does not trap, the return value
|
||||||
@@ -93,19 +88,19 @@ pub(crate) fn to_execution_result<E: Ext>(
|
|||||||
status: STATUS_SUCCESS,
|
status: STATUS_SUCCESS,
|
||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
Some(SpecialTrap::Termination) => {
|
Some(SpecialTrap::Termination) => {
|
||||||
return Ok(ExecReturnValue {
|
return Ok(ExecReturnValue {
|
||||||
status: STATUS_SUCCESS,
|
status: STATUS_SUCCESS,
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
Some(SpecialTrap::OutOfGas) => {
|
Some(SpecialTrap::OutOfGas) => {
|
||||||
return Err(ExecError {
|
return Err(ExecError {
|
||||||
reason: "ran out of gas during contract execution".into(),
|
reason: "ran out of gas during contract execution".into(),
|
||||||
buffer: runtime.scratch_buf,
|
buffer: runtime.scratch_buf,
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
None => (),
|
None => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,29 +110,43 @@ pub(crate) fn to_execution_result<E: Ext>(
|
|||||||
Ok(sp_sandbox::ReturnValue::Unit) => {
|
Ok(sp_sandbox::ReturnValue::Unit) => {
|
||||||
let mut buffer = runtime.scratch_buf;
|
let mut buffer = runtime.scratch_buf;
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
Ok(ExecReturnValue { status: STATUS_SUCCESS, data: buffer })
|
Ok(ExecReturnValue {
|
||||||
|
status: STATUS_SUCCESS,
|
||||||
|
data: buffer,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Ok(sp_sandbox::ReturnValue::Value(sp_sandbox::Value::I32(exit_code))) => {
|
Ok(sp_sandbox::ReturnValue::Value(sp_sandbox::Value::I32(exit_code))) => {
|
||||||
let status = (exit_code & 0xFF).try_into()
|
let status = (exit_code & 0xFF)
|
||||||
|
.try_into()
|
||||||
.expect("exit_code is masked into the range of a u8; qed");
|
.expect("exit_code is masked into the range of a u8; qed");
|
||||||
Ok(ExecReturnValue { status, data: runtime.scratch_buf })
|
Ok(ExecReturnValue {
|
||||||
|
status,
|
||||||
|
data: runtime.scratch_buf,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
// This should never happen as the return type of exported functions should have been
|
// This should never happen as the return type of exported functions should have been
|
||||||
// validated by the code preparation process. However, because panics are really
|
// validated by the code preparation process. However, because panics are really
|
||||||
// undesirable in the runtime code, we treat this as a trap for now. Eventually, we might
|
// undesirable in the runtime code, we treat this as a trap for now. Eventually, we might
|
||||||
// want to revisit this.
|
// want to revisit this.
|
||||||
Ok(_) => Err(ExecError { reason: "return type error".into(), buffer: runtime.scratch_buf }),
|
Ok(_) => Err(ExecError {
|
||||||
|
reason: "return type error".into(),
|
||||||
|
buffer: runtime.scratch_buf,
|
||||||
|
}),
|
||||||
// `Error::Module` is returned only if instantiation or linking failed (i.e.
|
// `Error::Module` is returned only if instantiation or linking failed (i.e.
|
||||||
// wasm binary tried to import a function that is not provided by the host).
|
// wasm binary tried to import a function that is not provided by the host).
|
||||||
// This shouldn't happen because validation process ought to reject such binaries.
|
// This shouldn't happen because validation process ought to reject such binaries.
|
||||||
//
|
//
|
||||||
// Because panics are really undesirable in the runtime code, we treat this as
|
// Because panics are really undesirable in the runtime code, we treat this as
|
||||||
// a trap for now. Eventually, we might want to revisit this.
|
// a trap for now. Eventually, we might want to revisit this.
|
||||||
Err(sp_sandbox::Error::Module) =>
|
Err(sp_sandbox::Error::Module) => Err(ExecError {
|
||||||
Err(ExecError { reason: "validation error".into(), buffer: runtime.scratch_buf }),
|
reason: "validation error".into(),
|
||||||
|
buffer: runtime.scratch_buf,
|
||||||
|
}),
|
||||||
// Any other kind of a trap should result in a failure.
|
// Any other kind of a trap should result in a failure.
|
||||||
Err(sp_sandbox::Error::Execution) | Err(sp_sandbox::Error::OutOfBounds) =>
|
Err(sp_sandbox::Error::Execution) | Err(sp_sandbox::Error::OutOfBounds) => Err(ExecError {
|
||||||
Err(ExecError { reason: "contract trapped during execution".into(), buffer: runtime.scratch_buf }),
|
reason: "contract trapped during execution".into(),
|
||||||
|
buffer: runtime.scratch_buf,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,14 +197,12 @@ impl<T: Trait> Token<T> for RuntimeToken {
|
|||||||
|
|
||||||
data_cost
|
data_cost
|
||||||
.and_then(|data_cost| {
|
.and_then(|data_cost| {
|
||||||
topics_cost.and_then(|topics_cost| {
|
topics_cost.and_then(|topics_cost| data_cost.checked_add(topics_cost))
|
||||||
data_cost.checked_add(topics_cost)
|
|
||||||
})
|
})
|
||||||
})
|
.and_then(|data_and_topics_cost| {
|
||||||
.and_then(|data_and_topics_cost|
|
|
||||||
data_and_topics_cost.checked_add(metadata.event_base_cost)
|
data_and_topics_cost.checked_add(metadata.event_base_cost)
|
||||||
)
|
})
|
||||||
},
|
}
|
||||||
DispatchWithWeight(gas) => gas.checked_add(metadata.dispatch_base_cost),
|
DispatchWithWeight(gas) => gas.checked_add(metadata.dispatch_base_cost),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -217,7 +224,7 @@ fn charge_gas<T: Trait, Tok: Token<T>>(
|
|||||||
GasMeterResult::OutOfGas => {
|
GasMeterResult::OutOfGas => {
|
||||||
*special_trap = Some(SpecialTrap::OutOfGas);
|
*special_trap = Some(SpecialTrap::OutOfGas);
|
||||||
Err(sp_sandbox::HostError)
|
Err(sp_sandbox::HostError)
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,7 +249,9 @@ fn read_sandbox_memory<E: Ext>(
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut buf = vec![0u8; len as usize];
|
let mut buf = vec![0u8; len as usize];
|
||||||
ctx.memory.get(ptr, buf.as_mut_slice()).map_err(|_| sp_sandbox::HostError)?;
|
ctx.memory
|
||||||
|
.get(ptr, buf.as_mut_slice())
|
||||||
|
.map_err(|_| sp_sandbox::HostError)?;
|
||||||
Ok(buf)
|
Ok(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,7 +276,9 @@ fn read_sandbox_memory_into_scratch<E: Ext>(
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
ctx.scratch_buf.resize(len as usize, 0);
|
ctx.scratch_buf.resize(len as usize, 0);
|
||||||
ctx.memory.get(ptr, ctx.scratch_buf.as_mut_slice()).map_err(|_| sp_sandbox::HostError)?;
|
ctx.memory
|
||||||
|
.get(ptr, ctx.scratch_buf.as_mut_slice())
|
||||||
|
.map_err(|_| sp_sandbox::HostError)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1165,14 +1176,10 @@ where
|
|||||||
/// the order of items is not preserved.
|
/// the order of items is not preserved.
|
||||||
fn has_duplicates<T: PartialEq + AsRef<[u8]>>(items: &mut Vec<T>) -> bool {
|
fn has_duplicates<T: PartialEq + AsRef<[u8]>>(items: &mut Vec<T>) -> bool {
|
||||||
// Sort the vector
|
// Sort the vector
|
||||||
items.sort_unstable_by(|a, b| {
|
items.sort_unstable_by(|a, b| Ord::cmp(a.as_ref(), b.as_ref()));
|
||||||
Ord::cmp(a.as_ref(), b.as_ref())
|
|
||||||
});
|
|
||||||
// And then find any two consecutive equal elements.
|
// And then find any two consecutive equal elements.
|
||||||
items.windows(2).any(|w| {
|
items.windows(2).any(|w| match w {
|
||||||
match w {
|
|
||||||
&[ref a, ref b] => a == b,
|
&[ref a, ref b] => a == b,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,8 @@
|
|||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
decl_event, decl_module, dispatch::DispatchResult,
|
decl_event, decl_module,
|
||||||
|
dispatch::DispatchResult,
|
||||||
traits::{Currency, ExistenceRequirement, WithdrawReason},
|
traits::{Currency, ExistenceRequirement, WithdrawReason},
|
||||||
};
|
};
|
||||||
use frame_system::ensure_signed;
|
use frame_system::ensure_signed;
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
[package]
|
||||||
|
name = "rococo-parachain-primitives"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# Substrate dependencies
|
||||||
|
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "rococo-branch" }
|
||||||
|
sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "rococo-branch" }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = [ "std" ]
|
||||||
|
std = [
|
||||||
|
"sp-runtime/std",
|
||||||
|
"sp-core/std"
|
||||||
|
]
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2020 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Cumulus.
|
||||||
|
|
||||||
|
// Substrate is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Substrate is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Primitives used by the Parachains Tick, Trick and Track.
|
||||||
|
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
|
use sp_runtime::{
|
||||||
|
generic,
|
||||||
|
traits::{BlakeTwo256, IdentifyAccount, Verify},
|
||||||
|
MultiSignature,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
|
||||||
|
|
||||||
|
/// Opaque block header type.
|
||||||
|
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
|
||||||
|
/// Opaque block type.
|
||||||
|
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
||||||
|
/// Opaque block identifier type.
|
||||||
|
pub type BlockId = generic::BlockId<Block>;
|
||||||
|
/// An index to a block.
|
||||||
|
pub type BlockNumber = u32;
|
||||||
|
|
||||||
|
/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
|
||||||
|
pub type Signature = MultiSignature;
|
||||||
|
|
||||||
|
/// Some way of identifying an account on the chain. We intentionally make it equivalent
|
||||||
|
/// to the public key of our transaction signing scheme.
|
||||||
|
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
|
||||||
|
|
||||||
|
/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
|
||||||
|
/// never know...
|
||||||
|
pub type AccountIndex = u32;
|
||||||
|
|
||||||
|
/// Balance of an account.
|
||||||
|
pub type Balance = u128;
|
||||||
|
|
||||||
|
/// Index of a transaction in the chain.
|
||||||
|
pub type Index = u32;
|
||||||
|
|
||||||
|
/// A hash of some data used by the chain.
|
||||||
|
pub type Hash = sp_core::H256;
|
||||||
|
|
||||||
|
/// Digest item type.
|
||||||
|
pub type DigestItem = generic::DigestItem<Hash>;
|
||||||
@@ -10,6 +10,7 @@ codec = { package = "parity-scale-codec", version = "1.3.0", default-features =
|
|||||||
|
|
||||||
cumulus-token-dealer = { path = "../pallets/token-dealer", default-features = false }
|
cumulus-token-dealer = { path = "../pallets/token-dealer", default-features = false }
|
||||||
parachain-info = { path = "../pallets/parachain-info", default-features = false }
|
parachain-info = { path = "../pallets/parachain-info", default-features = false }
|
||||||
|
rococo-parachain-primitives = { path = "../primitives", default-features = false }
|
||||||
|
|
||||||
# Substrate dependencies
|
# Substrate dependencies
|
||||||
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "rococo-branch" }
|
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "rococo-branch" }
|
||||||
@@ -71,6 +72,7 @@ std = [
|
|||||||
"pallet-sudo/std",
|
"pallet-sudo/std",
|
||||||
"pallet-transaction-payment/std",
|
"pallet-transaction-payment/std",
|
||||||
"parachain-info/std",
|
"parachain-info/std",
|
||||||
|
"rococo-parachain-primitives/std",
|
||||||
"cumulus-runtime/std",
|
"cumulus-runtime/std",
|
||||||
"cumulus-parachain-upgrade/std",
|
"cumulus-parachain-upgrade/std",
|
||||||
"cumulus-message-broker/std",
|
"cumulus-message-broker/std",
|
||||||
|
|||||||
@@ -22,13 +22,14 @@
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
||||||
|
|
||||||
|
use rococo_parachain_primitives::*;
|
||||||
use sp_api::impl_runtime_apis;
|
use sp_api::impl_runtime_apis;
|
||||||
use sp_core::OpaqueMetadata;
|
use sp_core::OpaqueMetadata;
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
create_runtime_str, generic, impl_opaque_keys,
|
create_runtime_str, generic, impl_opaque_keys,
|
||||||
traits::{BlakeTwo256, Block as BlockT, IdentifyAccount, IdentityLookup, Saturating, Verify},
|
traits::{BlakeTwo256, Block as BlockT, IdentityLookup, Saturating},
|
||||||
transaction_validity::{TransactionSource, TransactionValidity},
|
transaction_validity::{TransactionSource, TransactionValidity},
|
||||||
ApplyExtrinsicResult, MultiSignature,
|
ApplyExtrinsicResult,
|
||||||
};
|
};
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@@ -51,61 +52,18 @@ pub use pallet_timestamp::Call as TimestampCall;
|
|||||||
pub use sp_runtime::BuildStorage;
|
pub use sp_runtime::BuildStorage;
|
||||||
pub use sp_runtime::{Perbill, Permill};
|
pub use sp_runtime::{Perbill, Permill};
|
||||||
|
|
||||||
/// An index to a block.
|
|
||||||
pub type BlockNumber = u32;
|
|
||||||
|
|
||||||
/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
|
|
||||||
pub type Signature = MultiSignature;
|
|
||||||
|
|
||||||
/// Some way of identifying an account on the chain. We intentionally make it equivalent
|
|
||||||
/// to the public key of our transaction signing scheme.
|
|
||||||
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
|
|
||||||
|
|
||||||
/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
|
|
||||||
/// never know...
|
|
||||||
pub type AccountIndex = u32;
|
|
||||||
|
|
||||||
/// Balance of an account.
|
|
||||||
pub type Balance = u128;
|
|
||||||
|
|
||||||
/// Index of a transaction in the chain.
|
|
||||||
pub type Index = u32;
|
|
||||||
|
|
||||||
/// A hash of some data used by the chain.
|
|
||||||
pub type Hash = sp_core::H256;
|
|
||||||
|
|
||||||
/// Digest item type.
|
|
||||||
pub type DigestItem = generic::DigestItem<Hash>;
|
|
||||||
|
|
||||||
/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
|
|
||||||
/// the specifics of the runtime. They can then be made to be agnostic over specific formats
|
|
||||||
/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
|
|
||||||
/// to even the core datastructures.
|
|
||||||
pub mod opaque {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
|
|
||||||
|
|
||||||
/// Opaque block header type.
|
|
||||||
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
|
|
||||||
/// Opaque block type.
|
|
||||||
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
|
||||||
/// Opaque block identifier type.
|
|
||||||
pub type BlockId = generic::BlockId<Block>;
|
|
||||||
|
|
||||||
pub type SessionHandlers = ();
|
pub type SessionHandlers = ();
|
||||||
|
|
||||||
impl_opaque_keys! {
|
impl_opaque_keys! {
|
||||||
pub struct SessionKeys {}
|
pub struct SessionKeys {}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// This runtime version.
|
/// This runtime version.
|
||||||
pub const VERSION: RuntimeVersion = RuntimeVersion {
|
pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||||
spec_name: create_runtime_str!("cumulus-test-parachain"),
|
spec_name: create_runtime_str!("cumulus-test-parachain"),
|
||||||
impl_name: create_runtime_str!("cumulus-test-parachain"),
|
impl_name: create_runtime_str!("cumulus-test-parachain"),
|
||||||
authoring_version: 1,
|
authoring_version: 1,
|
||||||
spec_version: 1,
|
spec_version: 2,
|
||||||
impl_version: 1,
|
impl_version: 1,
|
||||||
apis: RUNTIME_API_VERSIONS,
|
apis: RUNTIME_API_VERSIONS,
|
||||||
transaction_version: 1,
|
transaction_version: 1,
|
||||||
@@ -266,8 +224,8 @@ impl parachain_info::Trait for Runtime {}
|
|||||||
construct_runtime! {
|
construct_runtime! {
|
||||||
pub enum Runtime where
|
pub enum Runtime where
|
||||||
Block = Block,
|
Block = Block,
|
||||||
NodeBlock = opaque::Block,
|
NodeBlock = rococo_parachain_primitives::Block,
|
||||||
UncheckedExtrinsic = UncheckedExtrinsic
|
UncheckedExtrinsic = UncheckedExtrinsic,
|
||||||
{
|
{
|
||||||
System: frame_system::{Module, Call, Storage, Config, Event<T>},
|
System: frame_system::{Module, Call, Storage, Config, Event<T>},
|
||||||
Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent},
|
Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent},
|
||||||
@@ -378,11 +336,11 @@ impl_runtime_apis! {
|
|||||||
fn decode_session_keys(
|
fn decode_session_keys(
|
||||||
encoded: Vec<u8>,
|
encoded: Vec<u8>,
|
||||||
) -> Option<Vec<(Vec<u8>, sp_core::crypto::KeyTypeId)>> {
|
) -> Option<Vec<(Vec<u8>, sp_core::crypto::KeyTypeId)>> {
|
||||||
opaque::SessionKeys::decode_into_raw_public_keys(&encoded)
|
SessionKeys::decode_into_raw_public_keys(&encoded)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
|
fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
|
||||||
opaque::SessionKeys::generate(seed)
|
SessionKeys::generate(seed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,19 +15,20 @@
|
|||||||
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use cumulus_primitives::ParaId;
|
use cumulus_primitives::ParaId;
|
||||||
use parachain_runtime::{
|
use hex_literal::hex;
|
||||||
AccountId, BalancesConfig, GenesisConfig, Signature, SudoConfig, SystemConfig,
|
use rococo_parachain_primitives::{AccountId, Signature};
|
||||||
ParachainInfoConfig, WASM_BINARY,
|
|
||||||
};
|
|
||||||
use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup};
|
use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup};
|
||||||
use sc_service::ChainType;
|
use sc_service::ChainType;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sp_core::{sr25519, Pair, Public};
|
use sp_core::{sr25519, Pair, Public};
|
||||||
use sp_runtime::traits::{IdentifyAccount, Verify};
|
use sp_runtime::traits::{IdentifyAccount, Verify};
|
||||||
use hex_literal::hex;
|
|
||||||
|
|
||||||
/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
|
/// Specialized `ChainSpec` for the normal parachain runtime.
|
||||||
pub type ChainSpec = sc_service::GenericChainSpec<GenesisConfig, Extensions>;
|
pub type ChainSpec = sc_service::GenericChainSpec<parachain_runtime::GenesisConfig, Extensions>;
|
||||||
|
|
||||||
|
/// Specialized `ChainSpec` for the contracts parachain runtime.
|
||||||
|
pub type ContractsChainSpec =
|
||||||
|
sc_service::GenericChainSpec<parachain_contracts_runtime::GenesisConfig, Extensions>;
|
||||||
|
|
||||||
/// Helper function to generate a crypto pair from seed
|
/// Helper function to generate a crypto pair from seed
|
||||||
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
|
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
|
||||||
@@ -99,6 +100,42 @@ pub fn get_chain_spec(id: ParaId) -> ChainSpec {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_contracts_chain_spec(id: ParaId) -> ContractsChainSpec {
|
||||||
|
ContractsChainSpec::from_genesis(
|
||||||
|
"Contracts Local Testnet",
|
||||||
|
"contracts_local_testnet",
|
||||||
|
ChainType::Local,
|
||||||
|
move || {
|
||||||
|
contracts_testnet_genesis(
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||||
|
vec![
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Bob"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Charlie"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Dave"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Eve"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Ferdie"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
|
||||||
|
],
|
||||||
|
id,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
vec![],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
Extensions {
|
||||||
|
relay_chain: "westend-dev".into(),
|
||||||
|
para_id: id.into(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn staging_test_net(id: ParaId) -> ChainSpec {
|
pub fn staging_test_net(id: ParaId) -> ChainSpec {
|
||||||
ChainSpec::from_genesis(
|
ChainSpec::from_genesis(
|
||||||
"Staging Testnet",
|
"Staging Testnet",
|
||||||
@@ -107,7 +144,9 @@ pub fn staging_test_net(id: ParaId) -> ChainSpec {
|
|||||||
move || {
|
move || {
|
||||||
testnet_genesis(
|
testnet_genesis(
|
||||||
hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into(),
|
hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into(),
|
||||||
vec![hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into()],
|
vec![
|
||||||
|
hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into(),
|
||||||
|
],
|
||||||
id,
|
id,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@@ -126,22 +165,47 @@ fn testnet_genesis(
|
|||||||
root_key: AccountId,
|
root_key: AccountId,
|
||||||
endowed_accounts: Vec<AccountId>,
|
endowed_accounts: Vec<AccountId>,
|
||||||
id: ParaId,
|
id: ParaId,
|
||||||
) -> GenesisConfig {
|
) -> parachain_runtime::GenesisConfig {
|
||||||
GenesisConfig {
|
parachain_runtime::GenesisConfig {
|
||||||
frame_system: Some(SystemConfig {
|
frame_system: Some(parachain_runtime::SystemConfig {
|
||||||
code: WASM_BINARY.expect("WASM binary was not build, please build it!").to_vec(),
|
code: parachain_runtime::WASM_BINARY
|
||||||
|
.expect("WASM binary was not build, please build it!")
|
||||||
|
.to_vec(),
|
||||||
changes_trie_config: Default::default(),
|
changes_trie_config: Default::default(),
|
||||||
}),
|
}),
|
||||||
pallet_balances: Some(BalancesConfig {
|
pallet_balances: Some(parachain_runtime::BalancesConfig {
|
||||||
balances: endowed_accounts
|
balances: endowed_accounts
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|k| (k, 1 << 60))
|
.map(|k| (k, 1 << 60))
|
||||||
.collect(),
|
.collect(),
|
||||||
}),
|
}),
|
||||||
pallet_sudo: Some(SudoConfig { key: root_key }),
|
pallet_sudo: Some(parachain_runtime::SudoConfig { key: root_key }),
|
||||||
parachain_info: Some(ParachainInfoConfig { parachain_id: id }),
|
parachain_info: Some(parachain_runtime::ParachainInfoConfig { parachain_id: id }),
|
||||||
// TODO: add contracts genesis for the contracts runtime
|
}
|
||||||
// pallet_contracts: Some(parachain_runtime::ContractsConfig { current_schedule: Default::default() }),
|
}
|
||||||
|
|
||||||
|
fn contracts_testnet_genesis(
|
||||||
|
root_key: AccountId,
|
||||||
|
endowed_accounts: Vec<AccountId>,
|
||||||
|
id: ParaId,
|
||||||
|
) -> parachain_contracts_runtime::GenesisConfig {
|
||||||
|
parachain_contracts_runtime::GenesisConfig {
|
||||||
|
frame_system: Some(parachain_contracts_runtime::SystemConfig {
|
||||||
|
code: parachain_contracts_runtime::WASM_BINARY
|
||||||
|
.expect("WASM binary was not build, please build it!")
|
||||||
|
.to_vec(),
|
||||||
|
changes_trie_config: Default::default(),
|
||||||
|
}),
|
||||||
|
pallet_balances: Some(parachain_contracts_runtime::BalancesConfig {
|
||||||
|
balances: endowed_accounts
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|k| (k, 1 << 60))
|
||||||
|
.collect(),
|
||||||
|
}),
|
||||||
|
pallet_sudo: Some(parachain_contracts_runtime::SudoConfig { key: root_key }),
|
||||||
|
parachain_info: Some(parachain_contracts_runtime::ParachainInfoConfig { parachain_id: id }),
|
||||||
|
cumulus_pallet_contracts: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ use log::info;
|
|||||||
use parachain_runtime::Block;
|
use parachain_runtime::Block;
|
||||||
use polkadot_parachain::primitives::AccountIdConversion;
|
use polkadot_parachain::primitives::AccountIdConversion;
|
||||||
use sc_cli::{
|
use sc_cli::{
|
||||||
ChainSpec, CliConfiguration, ImportParams, KeystoreParams, NetworkParams, Result,
|
ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams,
|
||||||
RuntimeVersion, SharedParams, SubstrateCli, DefaultConfigurationValues,
|
NetworkParams, Result, RuntimeVersion, SharedParams, SubstrateCli,
|
||||||
};
|
};
|
||||||
use sc_service::config::{BasePath, PrometheusConfig};
|
use sc_service::config::{BasePath, PrometheusConfig};
|
||||||
use sp_core::hexdisplay::HexDisplay;
|
use sp_core::hexdisplay::HexDisplay;
|
||||||
@@ -77,6 +77,9 @@ impl SubstrateCli for Cli {
|
|||||||
"track" => Ok(Box::new(chain_spec::ChainSpec::from_json_bytes(
|
"track" => Ok(Box::new(chain_spec::ChainSpec::from_json_bytes(
|
||||||
&include_bytes!("../res/track.json")[..],
|
&include_bytes!("../res/track.json")[..],
|
||||||
)?)),
|
)?)),
|
||||||
|
"contracts" => Ok(Box::new(chain_spec::get_contracts_chain_spec(
|
||||||
|
self.run.parachain_id.unwrap_or(100).into(),
|
||||||
|
))),
|
||||||
"" => Ok(Box::new(chain_spec::get_chain_spec(
|
"" => Ok(Box::new(chain_spec::get_chain_spec(
|
||||||
self.run.parachain_id.unwrap_or(100).into(),
|
self.run.parachain_id.unwrap_or(100).into(),
|
||||||
))),
|
))),
|
||||||
@@ -167,6 +170,10 @@ fn extract_genesis_wasm(chain_spec: &Box<dyn sc_service::ChainSpec>) -> Result<V
|
|||||||
.ok_or_else(|| "Could not find wasm file in genesis state!".into())
|
.ok_or_else(|| "Could not find wasm file in genesis state!".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn use_contracts_runtime(chain_spec: &Box<dyn ChainSpec>) -> bool {
|
||||||
|
chain_spec.id().starts_with("trick") || chain_spec.id().starts_with("contracts")
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse command line arguments into service configuration.
|
/// Parse command line arguments into service configuration.
|
||||||
pub fn run() -> Result<()> {
|
pub fn run() -> Result<()> {
|
||||||
let cli = Cli::from_args();
|
let cli = Cli::from_args();
|
||||||
@@ -175,8 +182,12 @@ pub fn run() -> Result<()> {
|
|||||||
Some(Subcommand::Base(subcommand)) => {
|
Some(Subcommand::Base(subcommand)) => {
|
||||||
let runner = cli.create_runner(subcommand)?;
|
let runner = cli.create_runner(subcommand)?;
|
||||||
|
|
||||||
|
if use_contracts_runtime(&runner.config().chain_spec) {
|
||||||
runner.run_subcommand(subcommand, |mut config| {
|
runner.run_subcommand(subcommand, |mut config| {
|
||||||
let params = crate::service::new_partial(&mut config)?;
|
let params = crate::service::new_partial::<
|
||||||
|
parachain_contracts_runtime::RuntimeApi,
|
||||||
|
crate::service::ContractsRuntimeExecutor,
|
||||||
|
>(&mut config)?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
params.client,
|
params.client,
|
||||||
@@ -185,6 +196,21 @@ pub fn run() -> Result<()> {
|
|||||||
params.task_manager,
|
params.task_manager,
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
runner.run_subcommand(subcommand, |mut config| {
|
||||||
|
let params = crate::service::new_partial::<
|
||||||
|
parachain_runtime::RuntimeApi,
|
||||||
|
crate::service::RuntimeExecutor,
|
||||||
|
>(&mut config)?;
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
params.client,
|
||||||
|
params.backend,
|
||||||
|
params.import_queue,
|
||||||
|
params.task_manager,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Some(Subcommand::ExportGenesisState(params)) => {
|
Some(Subcommand::ExportGenesisState(params)) => {
|
||||||
sc_cli::init_logger("");
|
sc_cli::init_logger("");
|
||||||
@@ -256,14 +282,23 @@ pub fn run() -> Result<()> {
|
|||||||
if cli.run.base.validator { "yes" } else { "no" }
|
if cli.run.base.validator { "yes" } else { "no" }
|
||||||
);
|
);
|
||||||
|
|
||||||
crate::service::run_node(
|
if use_contracts_runtime(&config.chain_spec) {
|
||||||
|
crate::service::start_contracts_node(
|
||||||
config,
|
config,
|
||||||
key,
|
key,
|
||||||
polkadot_config,
|
polkadot_config,
|
||||||
id,
|
id,
|
||||||
cli.run.base.validator,
|
cli.run.base.validator,
|
||||||
)
|
)
|
||||||
.map(|(x, _)| x)
|
} else {
|
||||||
|
crate::service::start_node(
|
||||||
|
config,
|
||||||
|
key,
|
||||||
|
polkadot_config,
|
||||||
|
id,
|
||||||
|
cli.run.base.validator,
|
||||||
|
).map(|r| r.0)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ async fn integration_test() {
|
|||||||
INTEGRATION_TEST_ALLOWED_TIME
|
INTEGRATION_TEST_ALLOWED_TIME
|
||||||
.and_then(|x| x.parse().ok())
|
.and_then(|x| x.parse().ok())
|
||||||
.unwrap_or(600),
|
.unwrap_or(600),
|
||||||
)).fuse();
|
))
|
||||||
|
.fuse();
|
||||||
|
|
||||||
let t2 = async {
|
let t2 = async {
|
||||||
let para_id = ParaId::from(100);
|
let para_id = ParaId::from(100);
|
||||||
@@ -105,7 +106,7 @@ async fn integration_test() {
|
|||||||
let parachain_config =
|
let parachain_config =
|
||||||
parachain_config(task_executor.clone(), Charlie, vec![], para_id).unwrap();
|
parachain_config(task_executor.clone(), Charlie, vec![], para_id).unwrap();
|
||||||
let (_service, charlie_client) =
|
let (_service, charlie_client) =
|
||||||
crate::service::run_node(parachain_config, key, polkadot_config, para_id, true)
|
crate::service::start_node(parachain_config, key, polkadot_config, para_id, true)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
sleep(Duration::from_secs(3)).await;
|
sleep(Duration::from_secs(3)).await;
|
||||||
charlie_client.wait_for_blocks(4).await;
|
charlie_client.wait_for_blocks(4).await;
|
||||||
|
|||||||
@@ -20,67 +20,74 @@ use cumulus_service::{
|
|||||||
prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams,
|
prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams,
|
||||||
};
|
};
|
||||||
use polkadot_primitives::v0::CollatorPair;
|
use polkadot_primitives::v0::CollatorPair;
|
||||||
|
use rococo_parachain_primitives::Block;
|
||||||
use sc_executor::native_executor_instance;
|
use sc_executor::native_executor_instance;
|
||||||
pub use sc_executor::NativeExecutor;
|
pub use sc_executor::NativeExecutor;
|
||||||
use sc_informant::OutputFormat;
|
use sc_informant::OutputFormat;
|
||||||
use sc_service::{Configuration, PartialComponents, Role, TFullBackend, TFullClient, TaskManager};
|
use sc_service::{Configuration, PartialComponents, Role, TFullBackend, TFullClient, TaskManager};
|
||||||
|
use sp_api::ConstructRuntimeApi;
|
||||||
use sp_runtime::traits::BlakeTwo256;
|
use sp_runtime::traits::BlakeTwo256;
|
||||||
use sp_trie::PrefixedMemoryDB;
|
use sp_trie::PrefixedMemoryDB;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
// Our native executor instance.
|
// Native executor instance.
|
||||||
native_executor_instance!(
|
native_executor_instance!(
|
||||||
pub Executor,
|
pub RuntimeExecutor,
|
||||||
parachain_runtime::api::dispatch,
|
parachain_runtime::api::dispatch,
|
||||||
parachain_runtime::native_version,
|
parachain_runtime::native_version,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Native executor instance for the contracts runtime.
|
||||||
|
native_executor_instance!(
|
||||||
|
pub ContractsRuntimeExecutor,
|
||||||
|
parachain_contracts_runtime::api::dispatch,
|
||||||
|
parachain_contracts_runtime::native_version,
|
||||||
|
);
|
||||||
|
|
||||||
/// Starts a `ServiceBuilder` for a full service.
|
/// Starts a `ServiceBuilder` for a full service.
|
||||||
///
|
///
|
||||||
/// Use this macro if you don't actually need the full service, but just the builder in order to
|
/// Use this macro if you don't actually need the full service, but just the builder in order to
|
||||||
/// be able to perform chain operations.
|
/// be able to perform chain operations.
|
||||||
pub fn new_partial(
|
pub fn new_partial<RuntimeApi, Executor>(
|
||||||
config: &mut Configuration,
|
config: &mut Configuration,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
PartialComponents<
|
PartialComponents<
|
||||||
TFullClient<
|
TFullClient<Block, RuntimeApi, Executor>,
|
||||||
parachain_runtime::opaque::Block,
|
TFullBackend<Block>,
|
||||||
parachain_runtime::RuntimeApi,
|
|
||||||
crate::service::Executor,
|
|
||||||
>,
|
|
||||||
TFullBackend<parachain_runtime::opaque::Block>,
|
|
||||||
(),
|
(),
|
||||||
sp_consensus::import_queue::BasicQueue<
|
sp_consensus::import_queue::BasicQueue<Block, PrefixedMemoryDB<BlakeTwo256>>,
|
||||||
parachain_runtime::opaque::Block,
|
sc_transaction_pool::FullPool<Block, TFullClient<Block, RuntimeApi, Executor>>,
|
||||||
PrefixedMemoryDB<BlakeTwo256>,
|
|
||||||
>,
|
|
||||||
sc_transaction_pool::FullPool<
|
|
||||||
parachain_runtime::opaque::Block,
|
|
||||||
TFullClient<
|
|
||||||
parachain_runtime::opaque::Block,
|
|
||||||
parachain_runtime::RuntimeApi,
|
|
||||||
crate::service::Executor,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
(),
|
(),
|
||||||
>,
|
>,
|
||||||
sc_service::Error,
|
sc_service::Error,
|
||||||
> {
|
>
|
||||||
|
where
|
||||||
|
RuntimeApi: ConstructRuntimeApi<Block, TFullClient<Block, RuntimeApi, Executor>>
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
|
RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
|
||||||
|
+ sp_api::Metadata<Block>
|
||||||
|
+ sp_session::SessionKeys<Block>
|
||||||
|
+ sp_api::ApiExt<
|
||||||
|
Block,
|
||||||
|
Error = sp_blockchain::Error,
|
||||||
|
StateBackend = sc_client_api::StateBackendFor<TFullBackend<Block>, Block>,
|
||||||
|
> + sp_offchain::OffchainWorkerApi<Block>
|
||||||
|
+ sp_block_builder::BlockBuilder<Block>,
|
||||||
|
sc_client_api::StateBackendFor<TFullBackend<Block>, Block>: sp_api::StateBackend<BlakeTwo256>,
|
||||||
|
Executor: sc_executor::NativeExecutionDispatch + 'static,
|
||||||
|
{
|
||||||
let inherent_data_providers = sp_inherents::InherentDataProviders::new();
|
let inherent_data_providers = sp_inherents::InherentDataProviders::new();
|
||||||
|
|
||||||
let (client, backend, keystore, task_manager) = sc_service::new_full_parts::<
|
let (client, backend, keystore, task_manager) =
|
||||||
parachain_runtime::opaque::Block,
|
sc_service::new_full_parts::<Block, RuntimeApi, Executor>(&config)?;
|
||||||
parachain_runtime::RuntimeApi,
|
|
||||||
crate::service::Executor,
|
|
||||||
>(&config)?;
|
|
||||||
let client = Arc::new(client);
|
let client = Arc::new(client);
|
||||||
//let select_chain = sc_consensus::LongestChain::new(backend.clone());
|
|
||||||
|
|
||||||
let registry = config.prometheus_registry();
|
let registry = config.prometheus_registry();
|
||||||
|
|
||||||
let transaction_pool = sc_transaction_pool::BasicPool::new_full(
|
let transaction_pool = sc_transaction_pool::BasicPool::new_full(
|
||||||
config.transaction_pool.clone(),
|
config.transaction_pool.clone(),
|
||||||
//std::sync::Arc::new(pool_api),
|
|
||||||
config.prometheus_registry(),
|
config.prometheus_registry(),
|
||||||
task_manager.spawn_handle(),
|
task_manager.spawn_handle(),
|
||||||
client.clone(),
|
client.clone(),
|
||||||
@@ -109,25 +116,39 @@ pub fn new_partial(
|
|||||||
Ok(params)
|
Ok(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run a node with the given parachain `Configuration` and relay chain `Configuration`
|
/// Start a node with the given parachain `Configuration` and relay chain `Configuration`.
|
||||||
///
|
///
|
||||||
/// This function blocks until done.
|
/// This is the actual implementation that is abstract over the executor and the runtime api.
|
||||||
pub fn run_node(
|
fn start_node_impl<RuntimeApi, Executor, RB>(
|
||||||
parachain_config: Configuration,
|
parachain_config: Configuration,
|
||||||
collator_key: Arc<CollatorPair>,
|
collator_key: Arc<CollatorPair>,
|
||||||
mut polkadot_config: polkadot_collator::Configuration,
|
mut polkadot_config: polkadot_collator::Configuration,
|
||||||
id: polkadot_primitives::v0::Id,
|
id: polkadot_primitives::v0::Id,
|
||||||
validator: bool,
|
validator: bool,
|
||||||
) -> sc_service::error::Result<(
|
rpc_ext_builder: RB,
|
||||||
TaskManager,
|
) -> sc_service::error::Result<(TaskManager, Arc<TFullClient<Block, RuntimeApi, Executor>>)>
|
||||||
Arc<
|
where
|
||||||
TFullClient<
|
RuntimeApi: ConstructRuntimeApi<Block, TFullClient<Block, RuntimeApi, Executor>>
|
||||||
parachain_runtime::opaque::Block,
|
+ Send
|
||||||
parachain_runtime::RuntimeApi,
|
+ Sync
|
||||||
crate::service::Executor,
|
+ 'static,
|
||||||
>,
|
RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
|
||||||
>,
|
+ sp_api::Metadata<Block>
|
||||||
)> {
|
+ sp_session::SessionKeys<Block>
|
||||||
|
+ sp_api::ApiExt<
|
||||||
|
Block,
|
||||||
|
Error = sp_blockchain::Error,
|
||||||
|
StateBackend = sc_client_api::StateBackendFor<TFullBackend<Block>, Block>,
|
||||||
|
> + sp_offchain::OffchainWorkerApi<Block>
|
||||||
|
+ sp_block_builder::BlockBuilder<Block>,
|
||||||
|
sc_client_api::StateBackendFor<TFullBackend<Block>, Block>: sp_api::StateBackend<BlakeTwo256>,
|
||||||
|
Executor: sc_executor::NativeExecutionDispatch + 'static,
|
||||||
|
RB: Fn(
|
||||||
|
Arc<TFullClient<Block, RuntimeApi, Executor>>,
|
||||||
|
) -> jsonrpc_core::IoHandler<sc_rpc::Metadata>
|
||||||
|
+ Send
|
||||||
|
+ 'static,
|
||||||
|
{
|
||||||
if matches!(parachain_config.role, Role::Light) {
|
if matches!(parachain_config.role, Role::Light) {
|
||||||
return Err("Light client not supported!".into());
|
return Err("Light client not supported!".into());
|
||||||
}
|
}
|
||||||
@@ -143,7 +164,7 @@ pub fn run_node(
|
|||||||
prefix: format!("[{}] ", Color::Blue.bold().paint("Relaychain")),
|
prefix: format!("[{}] ", Color::Blue.bold().paint("Relaychain")),
|
||||||
};
|
};
|
||||||
|
|
||||||
let params = new_partial(&mut parachain_config)?;
|
let params = new_partial::<RuntimeApi, Executor>(&mut parachain_config)?;
|
||||||
params
|
params
|
||||||
.inherent_data_providers
|
.inherent_data_providers
|
||||||
.register_provider(sp_timestamp::InherentDataProvider)
|
.register_provider(sp_timestamp::InherentDataProvider)
|
||||||
@@ -175,20 +196,9 @@ pub fn run_node(
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
let rpc_extensions_builder = {
|
let rpc_extensions_builder = {
|
||||||
let _client = client.clone();
|
let client = client.clone();
|
||||||
|
|
||||||
Box::new(move |_deny_unsafe| {
|
Box::new(move |_deny_unsafe| rpc_ext_builder(client.clone()))
|
||||||
let io = jsonrpc_core::IoHandler::default();
|
|
||||||
|
|
||||||
// TODO: add this rpc when running the contracts runtime
|
|
||||||
/*
|
|
||||||
use pallet_contracts_rpc::{Contracts, ContractsApi};
|
|
||||||
io.extend_with(
|
|
||||||
ContractsApi::to_delegate(Contracts::new(client.clone()))
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
io
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
sc_service::spawn_tasks(sc_service::SpawnTasksParams {
|
sc_service::spawn_tasks(sc_service::SpawnTasksParams {
|
||||||
@@ -249,3 +259,49 @@ pub fn run_node(
|
|||||||
|
|
||||||
Ok((task_manager, client))
|
Ok((task_manager, client))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Start a normal parachain node.
|
||||||
|
pub fn start_node(
|
||||||
|
parachain_config: Configuration,
|
||||||
|
collator_key: Arc<CollatorPair>,
|
||||||
|
polkadot_config: polkadot_collator::Configuration,
|
||||||
|
id: polkadot_primitives::v0::Id,
|
||||||
|
validator: bool,
|
||||||
|
) -> sc_service::error::Result<(
|
||||||
|
TaskManager,
|
||||||
|
Arc<TFullClient<Block, parachain_runtime::RuntimeApi, RuntimeExecutor>>,
|
||||||
|
)> {
|
||||||
|
start_node_impl::<parachain_runtime::RuntimeApi, RuntimeExecutor, _>(
|
||||||
|
parachain_config,
|
||||||
|
collator_key,
|
||||||
|
polkadot_config,
|
||||||
|
id,
|
||||||
|
validator,
|
||||||
|
|_| Default::default(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Start a contracts parachain node.
|
||||||
|
pub fn start_contracts_node(
|
||||||
|
parachain_config: Configuration,
|
||||||
|
collator_key: Arc<CollatorPair>,
|
||||||
|
polkadot_config: polkadot_collator::Configuration,
|
||||||
|
id: polkadot_primitives::v0::Id,
|
||||||
|
validator: bool,
|
||||||
|
) -> sc_service::error::Result<TaskManager> {
|
||||||
|
start_node_impl::<parachain_contracts_runtime::RuntimeApi, ContractsRuntimeExecutor, _>(
|
||||||
|
parachain_config,
|
||||||
|
collator_key,
|
||||||
|
polkadot_config,
|
||||||
|
id,
|
||||||
|
validator,
|
||||||
|
|client| {
|
||||||
|
let mut io = jsonrpc_core::IoHandler::default();
|
||||||
|
|
||||||
|
use cumulus_pallet_contracts_rpc::{Contracts, ContractsApi};
|
||||||
|
io.extend_with(ContractsApi::to_delegate(Contracts::new(client)));
|
||||||
|
io
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.map(|r| r.0)
|
||||||
|
}
|
||||||
|
|||||||
@@ -51,7 +51,9 @@ static mut STORAGE: Option<Box<dyn Storage>> = None;
|
|||||||
/// Panics if the [`STORAGE`] is not initialized.
|
/// Panics if the [`STORAGE`] is not initialized.
|
||||||
fn with_storage<R>(call: impl FnOnce(&mut dyn Storage) -> R) -> R {
|
fn with_storage<R>(call: impl FnOnce(&mut dyn Storage) -> R) -> R {
|
||||||
let mut storage = unsafe {
|
let mut storage = unsafe {
|
||||||
STORAGE.take().expect("`STORAGE` needs to be set before calling this function.")
|
STORAGE
|
||||||
|
.take()
|
||||||
|
.expect("`STORAGE` needs to be set before calling this function.")
|
||||||
};
|
};
|
||||||
|
|
||||||
let res = call(&mut *storage);
|
let res = call(&mut *storage);
|
||||||
@@ -142,7 +144,8 @@ pub fn validate_block<B: BlockT, E: ExecuteBlock<B>>(params: ValidationParams) -
|
|||||||
|
|
||||||
// If in the course of block execution new validation code was set, insert
|
// If in the course of block execution new validation code was set, insert
|
||||||
// its scheduled upgrade so we can validate that block number later.
|
// its scheduled upgrade so we can validate that block number later.
|
||||||
let new_validation_code = with_storage(|storage| storage.get(NEW_VALIDATION_CODE)).map(ValidationCode);
|
let new_validation_code =
|
||||||
|
with_storage(|storage| storage.get(NEW_VALIDATION_CODE)).map(ValidationCode);
|
||||||
if new_validation_code.is_some() && validation_function_params.code_upgrade_allowed.is_none() {
|
if new_validation_code.is_some() && validation_function_params.code_upgrade_allowed.is_none() {
|
||||||
panic!("Attempt to upgrade validation function when not permitted!");
|
panic!("Attempt to upgrade validation function when not permitted!");
|
||||||
}
|
}
|
||||||
@@ -154,7 +157,8 @@ pub fn validate_block<B: BlockT, E: ExecuteBlock<B>>(params: ValidationParams) -
|
|||||||
None => Vec::new(),
|
None => Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let processed_downward_messages = with_storage(|storage| storage.get(PROCESSED_DOWNWARD_MESSAGES))
|
let processed_downward_messages =
|
||||||
|
with_storage(|storage| storage.get(PROCESSED_DOWNWARD_MESSAGES))
|
||||||
.and_then(|v| Decode::decode(&mut &v[..]).ok())
|
.and_then(|v| Decode::decode(&mut &v[..]).ok())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
@@ -266,13 +270,11 @@ impl<B: BlockT> Storage for WitnessStorage<B> {
|
|||||||
let witness_data = &self.witness_data;
|
let witness_data = &self.witness_data;
|
||||||
let storage_root = &self.storage_root;
|
let storage_root = &self.storage_root;
|
||||||
|
|
||||||
let current_value = overlay.entry(key.to_vec()).or_insert_with(||
|
let current_value = overlay.entry(key.to_vec()).or_insert_with(|| {
|
||||||
read_trie_value::<Layout<HashFor<B>>, _>(
|
read_trie_value::<Layout<HashFor<B>>, _>(witness_data, storage_root, key)
|
||||||
witness_data,
|
.ok()
|
||||||
storage_root,
|
.flatten()
|
||||||
key,
|
});
|
||||||
).ok().flatten()
|
|
||||||
);
|
|
||||||
|
|
||||||
let item = current_value.take().unwrap_or_default();
|
let item = current_value.take().unwrap_or_default();
|
||||||
*current_value = Some(
|
*current_value = Some(
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ fn build_block_with_proof(
|
|||||||
built_block.block,
|
built_block.block,
|
||||||
built_block
|
built_block
|
||||||
.proof
|
.proof
|
||||||
.expect("We enabled proof recording before.")
|
.expect("We enabled proof recording before."),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user