mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 16:57:58 +00:00
[contracts] Implement transparent hashing for contract storage (#11501)
* save * builds and old tests pass save: temporary value dropped while borrowed save: finally builds test updated but still fails * type names enhanced * VarSizedKey bounded to new Config param * improved wasm runtime updated funcs * unstable-interface tests fixed * benchmarks fixed * Apply suggestions from code review Co-authored-by: Alexander Theißen <alex.theissen@me.com> * fixes on feedback * fixes on feedback applied + make it build * benchmarks build but fail (old) * "Original code too large" * seal_clear_storage bench fixed (code size workaround hack removal tbd) * bench_seal_clear_storage pass * bench_seal_take_storage ... ok * added new seal_set_storage + updated benchmarks * added new seal_get_storage + updated benchmarks * added new seal_contains_storage + updated benchmarks * added tests for _transparent exec functions * wasm test for clear_storage * wasm test for take_storage * wasm test for new set_storage * wasm test for new get_storage * wasm test for new contains_storage * CI fix * ci fix * ci fix * ci fix * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * fixes according to the review feedback * tests & benchmarks fixed * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * refactoring * fix to runtime api * ci fix * ctx.get_storage() factored out * ctx.contains_storage() factored out * number of batches reduced for transparent hashing storage benchmarks * contracts RPC & pallet::get_storage to use transparent hashing * node and rpc updated to use get_storage with VarSizedKey * refactored (more concize) * refactored contains_storage (DRYed) * refactored contains_storage (DRYed) * fix rpc * fmt fix * more fixes in rpc * rollback `Pallet:get_storage` to Vec<u8> and rpc and node parts related to it * added `KeyDecodingFailed` error * Revert weird "fmt fix" This reverts commit c582cfff4b5cb2c9929fd5e3b45519bb24aeb657. * node-executor basic test update * fix node-executor basic test * benchmarks fix * more benchmarks fix * FixedSizedKey is hidden from pub, VarSizedKey is exported as StorageKey * ci fix * set_storage benchmark fix * ci fix * ci fix * comments improved * new error code to rpc: KEY_DECODING_FAILED * Put `rusty-cachier` before PR merge into `master` for `cargo-check-benches` job * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * minor optimization Co-authored-by: Alexander Theißen <alex.theissen@me.com> Co-authored-by: Parity Bot <admin@parity.io> Co-authored-by: Vladimir Istyufeev <vladimir@parity.io> Co-authored-by: command-bot <>
This commit is contained in:
committed by
GitHub
parent
7d2ecc8995
commit
68ea2ab039
@@ -27,12 +27,13 @@ use frame_support::{
|
||||
storage::{with_transaction, TransactionOutcome},
|
||||
traits::{Contains, Currency, ExistenceRequirement, OriginTrait, Randomness, Time},
|
||||
weights::Weight,
|
||||
Blake2_128Concat, BoundedVec, StorageHasher,
|
||||
};
|
||||
use frame_system::RawOrigin;
|
||||
use pallet_contracts_primitives::ExecReturnValue;
|
||||
use smallvec::{Array, SmallVec};
|
||||
use sp_core::{crypto::UncheckedFrom, ecdsa::Public as ECDSAPublic};
|
||||
use sp_io::crypto::secp256k1_ecdsa_recover_compressed;
|
||||
use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256};
|
||||
use sp_runtime::traits::Convert;
|
||||
use sp_std::{marker::PhantomData, mem, prelude::*};
|
||||
|
||||
@@ -40,12 +41,40 @@ pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
|
||||
pub type MomentOf<T> = <<T as Config>::Time as Time>::Moment;
|
||||
pub type SeedOf<T> = <T as frame_system::Config>::Hash;
|
||||
pub type BlockNumberOf<T> = <T as frame_system::Config>::BlockNumber;
|
||||
pub type StorageKey = [u8; 32];
|
||||
pub type ExecResult = Result<ExecReturnValue, ExecError>;
|
||||
|
||||
/// A type that represents a topic of an event. At the moment a hash is used.
|
||||
pub type TopicOf<T> = <T as frame_system::Config>::Hash;
|
||||
|
||||
/// Type for fix sized storage key.
|
||||
pub type FixSizedKey = [u8; 32];
|
||||
|
||||
/// Type for variable sized storage key. Used for transparent hashing.
|
||||
pub type VarSizedKey<T> = BoundedVec<u8, <T as Config>::MaxStorageKeyLen>;
|
||||
|
||||
/// Trait for hashing storage keys.
|
||||
pub trait StorageKey<T>
|
||||
where
|
||||
T: Config,
|
||||
{
|
||||
fn hash(&self) -> Vec<u8>;
|
||||
}
|
||||
|
||||
impl<T: Config> StorageKey<T> for FixSizedKey {
|
||||
fn hash(&self) -> Vec<u8> {
|
||||
blake2_256(self.as_slice()).to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> StorageKey<T> for VarSizedKey<T>
|
||||
where
|
||||
T: Config,
|
||||
{
|
||||
fn hash(&self) -> Vec<u8> {
|
||||
Blake2_128Concat::hash(self.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
/// Origin of the error.
|
||||
///
|
||||
/// Call or instantiate both called into other contracts and pass through errors happening
|
||||
@@ -140,19 +169,44 @@ pub trait Ext: sealing::Sealed {
|
||||
///
|
||||
/// Returns `None` if the `key` wasn't previously set by `set_storage` or
|
||||
/// was deleted.
|
||||
fn get_storage(&mut self, key: &StorageKey) -> Option<Vec<u8>>;
|
||||
fn get_storage(&mut self, key: &FixSizedKey) -> Option<Vec<u8>>;
|
||||
|
||||
/// This is a variation of `get_storage()` to be used with transparent hashing.
|
||||
/// These two will be merged into a single function after some refactoring is done.
|
||||
/// Returns the storage entry of the executing account by the given `key`.
|
||||
///
|
||||
/// Returns `None` if the `key` wasn't previously set by `set_storage` or
|
||||
/// was deleted.
|
||||
fn get_storage_transparent(&mut self, key: &VarSizedKey<Self::T>) -> Option<Vec<u8>>;
|
||||
|
||||
/// Returns `Some(len)` (in bytes) if a storage item exists at `key`.
|
||||
///
|
||||
/// Returns `None` if the `key` wasn't previously set by `set_storage` or
|
||||
/// was deleted.
|
||||
fn get_storage_size(&mut self, key: &StorageKey) -> Option<u32>;
|
||||
fn get_storage_size(&mut self, key: &FixSizedKey) -> Option<u32>;
|
||||
|
||||
/// This is the variation of `get_storage_size()` to be used with transparent hashing.
|
||||
/// These two will be merged into a single function after some refactoring is done.
|
||||
/// Returns `Some(len)` (in bytes) if a storage item exists at `key`.
|
||||
///
|
||||
/// Returns `None` if the `key` wasn't previously set by `set_storage` or
|
||||
/// was deleted.
|
||||
fn get_storage_size_transparent(&mut self, key: &VarSizedKey<Self::T>) -> Option<u32>;
|
||||
|
||||
/// Sets the storage entry by the given key to the specified value. If `value` is `None` then
|
||||
/// the storage entry is deleted.
|
||||
fn set_storage(
|
||||
&mut self,
|
||||
key: StorageKey,
|
||||
key: &FixSizedKey,
|
||||
value: Option<Vec<u8>>,
|
||||
take_old: bool,
|
||||
) -> Result<WriteOutcome, DispatchError>;
|
||||
|
||||
/// This is the variation of `set_storage()` to be used with transparent hashing.
|
||||
/// These two will be merged into a single function after some refactoring is done.
|
||||
fn set_storage_transparent(
|
||||
&mut self,
|
||||
key: &VarSizedKey<Self::T>,
|
||||
value: Option<Vec<u8>>,
|
||||
take_old: bool,
|
||||
) -> Result<WriteOutcome, DispatchError>;
|
||||
@@ -1085,24 +1139,48 @@ where
|
||||
Self::transfer(ExistenceRequirement::KeepAlive, &self.top_frame().account_id, to, value)
|
||||
}
|
||||
|
||||
fn get_storage(&mut self, key: &StorageKey) -> Option<Vec<u8>> {
|
||||
fn get_storage(&mut self, key: &FixSizedKey) -> Option<Vec<u8>> {
|
||||
Storage::<T>::read(&self.top_frame_mut().contract_info().trie_id, key)
|
||||
}
|
||||
|
||||
fn get_storage_size(&mut self, key: &StorageKey) -> Option<u32> {
|
||||
fn get_storage_transparent(&mut self, key: &VarSizedKey<T>) -> Option<Vec<u8>> {
|
||||
Storage::<T>::read(&self.top_frame_mut().contract_info().trie_id, key)
|
||||
}
|
||||
|
||||
fn get_storage_size(&mut self, key: &FixSizedKey) -> Option<u32> {
|
||||
Storage::<T>::size(&self.top_frame_mut().contract_info().trie_id, key)
|
||||
}
|
||||
|
||||
fn get_storage_size_transparent(&mut self, key: &VarSizedKey<T>) -> Option<u32> {
|
||||
Storage::<T>::size(&self.top_frame_mut().contract_info().trie_id, key)
|
||||
}
|
||||
|
||||
fn set_storage(
|
||||
&mut self,
|
||||
key: StorageKey,
|
||||
key: &FixSizedKey,
|
||||
value: Option<Vec<u8>>,
|
||||
take_old: bool,
|
||||
) -> Result<WriteOutcome, DispatchError> {
|
||||
let frame = self.top_frame_mut();
|
||||
Storage::<T>::write(
|
||||
&frame.contract_info.get(&frame.account_id).trie_id,
|
||||
&key,
|
||||
key,
|
||||
value,
|
||||
Some(&mut frame.nested_storage),
|
||||
take_old,
|
||||
)
|
||||
}
|
||||
|
||||
fn set_storage_transparent(
|
||||
&mut self,
|
||||
key: &VarSizedKey<T>,
|
||||
value: Option<Vec<u8>>,
|
||||
take_old: bool,
|
||||
) -> Result<WriteOutcome, DispatchError> {
|
||||
let frame = self.top_frame_mut();
|
||||
Storage::<T>::write(
|
||||
&frame.contract_info.get(&frame.account_id).trie_id,
|
||||
key,
|
||||
value,
|
||||
Some(&mut frame.nested_storage),
|
||||
take_old,
|
||||
@@ -2635,35 +2713,35 @@ mod tests {
|
||||
let code_hash = MockLoader::insert(Call, |ctx, _| {
|
||||
// Write
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage([1; 32], Some(vec![1, 2, 3]), false),
|
||||
ctx.ext.set_storage(&[1; 32], Some(vec![1, 2, 3]), false),
|
||||
Ok(WriteOutcome::New)
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage([2; 32], Some(vec![4, 5, 6]), true),
|
||||
ctx.ext.set_storage(&[2; 32], Some(vec![4, 5, 6]), true),
|
||||
Ok(WriteOutcome::New)
|
||||
);
|
||||
assert_eq!(ctx.ext.set_storage([3; 32], None, false), Ok(WriteOutcome::New));
|
||||
assert_eq!(ctx.ext.set_storage([4; 32], None, true), Ok(WriteOutcome::New));
|
||||
assert_eq!(ctx.ext.set_storage([5; 32], Some(vec![]), false), Ok(WriteOutcome::New));
|
||||
assert_eq!(ctx.ext.set_storage([6; 32], Some(vec![]), true), Ok(WriteOutcome::New));
|
||||
assert_eq!(ctx.ext.set_storage(&[3; 32], None, false), Ok(WriteOutcome::New));
|
||||
assert_eq!(ctx.ext.set_storage(&[4; 32], None, true), Ok(WriteOutcome::New));
|
||||
assert_eq!(ctx.ext.set_storage(&[5; 32], Some(vec![]), false), Ok(WriteOutcome::New));
|
||||
assert_eq!(ctx.ext.set_storage(&[6; 32], Some(vec![]), true), Ok(WriteOutcome::New));
|
||||
|
||||
// Overwrite
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage([1; 32], Some(vec![42]), false),
|
||||
ctx.ext.set_storage(&[1; 32], Some(vec![42]), false),
|
||||
Ok(WriteOutcome::Overwritten(3))
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage([2; 32], Some(vec![48]), true),
|
||||
ctx.ext.set_storage(&[2; 32], Some(vec![48]), true),
|
||||
Ok(WriteOutcome::Taken(vec![4, 5, 6]))
|
||||
);
|
||||
assert_eq!(ctx.ext.set_storage([3; 32], None, false), Ok(WriteOutcome::New));
|
||||
assert_eq!(ctx.ext.set_storage([4; 32], None, true), Ok(WriteOutcome::New));
|
||||
assert_eq!(ctx.ext.set_storage(&[3; 32], None, false), Ok(WriteOutcome::New));
|
||||
assert_eq!(ctx.ext.set_storage(&[4; 32], None, true), Ok(WriteOutcome::New));
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage([5; 32], Some(vec![]), false),
|
||||
ctx.ext.set_storage(&[5; 32], Some(vec![]), false),
|
||||
Ok(WriteOutcome::Overwritten(0))
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage([6; 32], Some(vec![]), true),
|
||||
ctx.ext.set_storage(&[6; 32], Some(vec![]), true),
|
||||
Ok(WriteOutcome::Taken(vec![]))
|
||||
);
|
||||
|
||||
@@ -2690,14 +2768,175 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_storage_transparent_works() {
|
||||
let code_hash = MockLoader::insert(Call, |ctx, _| {
|
||||
// Write
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([1; 64].to_vec()).unwrap(),
|
||||
Some(vec![1, 2, 3]),
|
||||
false
|
||||
),
|
||||
Ok(WriteOutcome::New)
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([2; 19].to_vec()).unwrap(),
|
||||
Some(vec![4, 5, 6]),
|
||||
true
|
||||
),
|
||||
Ok(WriteOutcome::New)
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([3; 19].to_vec()).unwrap(),
|
||||
None,
|
||||
false
|
||||
),
|
||||
Ok(WriteOutcome::New)
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([4; 64].to_vec()).unwrap(),
|
||||
None,
|
||||
true
|
||||
),
|
||||
Ok(WriteOutcome::New)
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([5; 30].to_vec()).unwrap(),
|
||||
Some(vec![]),
|
||||
false
|
||||
),
|
||||
Ok(WriteOutcome::New)
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([6; 128].to_vec()).unwrap(),
|
||||
Some(vec![]),
|
||||
true
|
||||
),
|
||||
Ok(WriteOutcome::New)
|
||||
);
|
||||
|
||||
// Overwrite
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([1; 64].to_vec()).unwrap(),
|
||||
Some(vec![42, 43, 44]),
|
||||
false
|
||||
),
|
||||
Ok(WriteOutcome::Overwritten(3))
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([2; 19].to_vec()).unwrap(),
|
||||
Some(vec![48]),
|
||||
true
|
||||
),
|
||||
Ok(WriteOutcome::Taken(vec![4, 5, 6]))
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([3; 19].to_vec()).unwrap(),
|
||||
None,
|
||||
false
|
||||
),
|
||||
Ok(WriteOutcome::New)
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([4; 64].to_vec()).unwrap(),
|
||||
None,
|
||||
true
|
||||
),
|
||||
Ok(WriteOutcome::New)
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([5; 30].to_vec()).unwrap(),
|
||||
Some(vec![]),
|
||||
false
|
||||
),
|
||||
Ok(WriteOutcome::Overwritten(0))
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([6; 128].to_vec()).unwrap(),
|
||||
Some(vec![]),
|
||||
true
|
||||
),
|
||||
Ok(WriteOutcome::Taken(vec![]))
|
||||
);
|
||||
|
||||
exec_success()
|
||||
});
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let min_balance = <Test as Config>::Currency::minimum_balance();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
|
||||
set_balance(&ALICE, min_balance * 1000);
|
||||
place_contract(&BOB, code_hash);
|
||||
let mut storage_meter = storage::meter::Meter::new(&ALICE, None, 0).unwrap();
|
||||
assert_ok!(MockStack::run_call(
|
||||
ALICE,
|
||||
BOB,
|
||||
&mut gas_meter,
|
||||
&mut storage_meter,
|
||||
&schedule,
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_storage_works() {
|
||||
let code_hash = MockLoader::insert(Call, |ctx, _| {
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage(&[1; 32], Some(vec![1, 2, 3]), false),
|
||||
Ok(WriteOutcome::New)
|
||||
);
|
||||
assert_eq!(ctx.ext.set_storage(&[2; 32], Some(vec![]), false), Ok(WriteOutcome::New));
|
||||
assert_eq!(ctx.ext.get_storage(&[1; 32]), Some(vec![1, 2, 3]));
|
||||
assert_eq!(ctx.ext.get_storage(&[2; 32]), Some(vec![]));
|
||||
assert_eq!(ctx.ext.get_storage(&[3; 32]), None);
|
||||
|
||||
exec_success()
|
||||
});
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let min_balance = <Test as Config>::Currency::minimum_balance();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
|
||||
set_balance(&ALICE, min_balance * 1000);
|
||||
place_contract(&BOB, code_hash);
|
||||
let mut storage_meter = storage::meter::Meter::new(&ALICE, None, 0).unwrap();
|
||||
assert_ok!(MockStack::run_call(
|
||||
ALICE,
|
||||
BOB,
|
||||
&mut gas_meter,
|
||||
&mut storage_meter,
|
||||
&schedule,
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_storage_size_works() {
|
||||
let code_hash = MockLoader::insert(Call, |ctx, _| {
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage([1; 32], Some(vec![1, 2, 3]), false),
|
||||
ctx.ext.set_storage(&[1; 32], Some(vec![1, 2, 3]), false),
|
||||
Ok(WriteOutcome::New)
|
||||
);
|
||||
assert_eq!(ctx.ext.set_storage([2; 32], Some(vec![]), false), Ok(WriteOutcome::New));
|
||||
assert_eq!(ctx.ext.set_storage(&[2; 32], Some(vec![]), false), Ok(WriteOutcome::New));
|
||||
assert_eq!(ctx.ext.get_storage_size(&[1; 32]), Some(3));
|
||||
assert_eq!(ctx.ext.get_storage_size(&[2; 32]), Some(0));
|
||||
assert_eq!(ctx.ext.get_storage_size(&[3; 32]), None);
|
||||
@@ -2724,6 +2963,129 @@ mod tests {
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_storage_transparent_works() {
|
||||
let code_hash = MockLoader::insert(Call, |ctx, _| {
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([1; 19].to_vec()).unwrap(),
|
||||
Some(vec![1, 2, 3]),
|
||||
false
|
||||
),
|
||||
Ok(WriteOutcome::New)
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([2; 16].to_vec()).unwrap(),
|
||||
Some(vec![]),
|
||||
false
|
||||
),
|
||||
Ok(WriteOutcome::New)
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.get_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([1; 19].to_vec()).unwrap()
|
||||
),
|
||||
Some(vec![1, 2, 3])
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.get_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([2; 16].to_vec()).unwrap()
|
||||
),
|
||||
Some(vec![])
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.get_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([3; 8].to_vec()).unwrap()
|
||||
),
|
||||
None
|
||||
);
|
||||
|
||||
exec_success()
|
||||
});
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let min_balance = <Test as Config>::Currency::minimum_balance();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
|
||||
set_balance(&ALICE, min_balance * 1000);
|
||||
place_contract(&BOB, code_hash);
|
||||
let mut storage_meter = storage::meter::Meter::new(&ALICE, None, 0).unwrap();
|
||||
assert_ok!(MockStack::run_call(
|
||||
ALICE,
|
||||
BOB,
|
||||
&mut gas_meter,
|
||||
&mut storage_meter,
|
||||
&schedule,
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_storage_size_transparent_works() {
|
||||
let code_hash = MockLoader::insert(Call, |ctx, _| {
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([1; 19].to_vec()).unwrap(),
|
||||
Some(vec![1, 2, 3]),
|
||||
false
|
||||
),
|
||||
Ok(WriteOutcome::New)
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.set_storage_transparent(
|
||||
&VarSizedKey::<Test>::try_from([2; 16].to_vec()).unwrap(),
|
||||
Some(vec![]),
|
||||
false
|
||||
),
|
||||
Ok(WriteOutcome::New)
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.get_storage_size_transparent(
|
||||
&VarSizedKey::<Test>::try_from([1; 19].to_vec()).unwrap()
|
||||
),
|
||||
Some(3)
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.get_storage_size_transparent(
|
||||
&VarSizedKey::<Test>::try_from([2; 16].to_vec()).unwrap()
|
||||
),
|
||||
Some(0)
|
||||
);
|
||||
assert_eq!(
|
||||
ctx.ext.get_storage_size_transparent(
|
||||
&VarSizedKey::<Test>::try_from([3; 8].to_vec()).unwrap()
|
||||
),
|
||||
None
|
||||
);
|
||||
|
||||
exec_success()
|
||||
});
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let min_balance = <Test as Config>::Currency::minimum_balance();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
|
||||
set_balance(&ALICE, min_balance * 1000);
|
||||
place_contract(&BOB, code_hash);
|
||||
let mut storage_meter = storage::meter::Meter::new(&ALICE, None, 0).unwrap();
|
||||
assert_ok!(MockStack::run_call(
|
||||
ALICE,
|
||||
BOB,
|
||||
&mut gas_meter,
|
||||
&mut storage_meter,
|
||||
&schedule,
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ecdsa_to_eth_address_returns_proper_value() {
|
||||
let bob_ch = MockLoader::insert(Call, |ctx, _| {
|
||||
|
||||
Reference in New Issue
Block a user