Skip to content

Commit

Permalink
Add additionally functionality to contracts storage interface (parity…
Browse files Browse the repository at this point in the history
…tech#10497)

* Add new versions for storage access host functions

* Improve docs
  • Loading branch information
athei authored and ark0f committed Feb 27, 2023
1 parent 5a0b5b2 commit f831307
Show file tree
Hide file tree
Showing 8 changed files with 1,392 additions and 600 deletions.
177 changes: 169 additions & 8 deletions frame/contracts/src/benchmarking/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ where
fn store(&self, items: &Vec<(StorageKey, Vec<u8>)>) -> Result<(), &'static str> {
let info = self.info()?;
for item in items {
Storage::<T>::write(&info.trie_id, &item.0, Some(item.1.clone()), None)
Storage::<T>::write(&info.trie_id, &item.0, Some(item.1.clone()), None, false)
.map_err(|_| "Failed to write storage to restoration dest")?;
}
<ContractInfoOf<T>>::insert(&self.account_id, info.clone());
Expand Down Expand Up @@ -784,10 +784,10 @@ benchmarks! {
let code = WasmModule::<T>::from(ModuleDefinition {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "seal0",
module: "__unstable__",
name: "seal_set_storage",
params: vec![ValueType::I32, ValueType::I32, ValueType::I32],
return_type: None,
return_type: Some(ValueType::I32),
}],
data_segments: vec![
DataSegment {
Expand All @@ -800,6 +800,7 @@ benchmarks! {
Regular(Instruction::I32Const(0)), // value_ptr
Regular(Instruction::I32Const(0)), // value_len
Regular(Instruction::Call(0)),
Regular(Instruction::Drop),
])),
.. Default::default()
});
Expand All @@ -814,10 +815,10 @@ benchmarks! {
let code = WasmModule::<T>::from(ModuleDefinition {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "seal0",
module: "__unstable__",
name: "seal_set_storage",
params: vec![ValueType::I32, ValueType::I32, ValueType::I32],
return_type: None,
return_type: Some(ValueType::I32),
}],
data_segments: vec![
DataSegment {
Expand All @@ -830,6 +831,7 @@ benchmarks! {
Instruction::I32Const(0), // value_ptr
Instruction::I32Const((n * 1024) as i32), // value_len
Instruction::Call(0),
Instruction::Drop,
])),
.. Default::default()
});
Expand All @@ -851,10 +853,10 @@ benchmarks! {
let code = WasmModule::<T>::from(ModuleDefinition {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "seal0",
module: "__unstable__",
name: "seal_clear_storage",
params: vec![ValueType::I32],
return_type: None,
return_type: Some(ValueType::I32),
}],
data_segments: vec![
DataSegment {
Expand All @@ -865,6 +867,7 @@ benchmarks! {
call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![
Counter(0, key_len as u32),
Regular(Instruction::Call(0)),
Regular(Instruction::Drop),
])),
.. Default::default()
});
Expand All @@ -876,6 +879,7 @@ benchmarks! {
key.as_slice().try_into().map_err(|e| "Key has wrong length")?,
Some(vec![42; T::Schedule::get().limits.payload_len as usize]),
None,
false,
)
.map_err(|_| "Failed to write to storage during setup.")?;
}
Expand Down Expand Up @@ -906,6 +910,10 @@ benchmarks! {
offset: 0,
value: key_bytes,
},
DataSegment {
offset: key_bytes_len as u32,
value: T::Schedule::get().limits.payload_len.to_le_bytes().into(),
},
],
call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![
Counter(0, key_len as u32), // key_ptr
Expand All @@ -924,6 +932,54 @@ benchmarks! {
key.as_slice().try_into().map_err(|e| "Key has wrong length")?,
Some(vec![]),
None,
false,
)
.map_err(|_| "Failed to write to storage during setup.")?;
}
<ContractInfoOf<T>>::insert(&instance.account_id, info.clone());
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])

// We make sure that all storage accesses are to unique keys.
#[skip_meta]
seal_contains_storage {
let r in 0 .. API_BENCHMARK_BATCHES;
let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE)
.map(|n| T::Hashing::hash_of(&n).as_ref().to_vec())
.collect::<Vec<_>>();
let key_len = sp_std::mem::size_of::<<T::Hashing as sp_runtime::traits::Hash>::Output>();
let key_bytes = keys.iter().flatten().cloned().collect::<Vec<_>>();
let key_bytes_len = key_bytes.len();
let code = WasmModule::<T>::from(ModuleDefinition {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "__unstable__",
name: "seal_contains_storage",
params: vec![ValueType::I32],
return_type: Some(ValueType::I32),
}],
data_segments: vec![
DataSegment {
offset: 0,
value: key_bytes,
},
],
call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![
Counter(0, key_len as u32), // key_ptr
Regular(Instruction::Call(0)),
Regular(Instruction::Drop),
])),
.. Default::default()
});
let instance = Contract::<T>::new(code, vec![])?;
let info = instance.info()?;
for key in keys {
Storage::<T>::write(
&info.trie_id,
key.as_slice().try_into().map_err(|e| "Key has wrong length")?,
Some(vec![42; T::Schedule::get().limits.payload_len as usize]),
None,
false,
)
.map_err(|_| "Failed to write to storage during setup.")?;
}
Expand Down Expand Up @@ -970,12 +1026,117 @@ benchmarks! {
key.as_slice().try_into().map_err(|e| "Key has wrong length")?,
Some(vec![42u8; (n * 1024) as usize]),
None,
false,
)
.map_err(|_| "Failed to write to storage during setup.")?;
<ContractInfoOf<T>>::insert(&instance.account_id, info.clone());
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])

#[skip_meta]
seal_take_storage {
let r in 0 .. API_BENCHMARK_BATCHES;
let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE)
.map(|n| T::Hashing::hash_of(&n).as_ref().to_vec())
.collect::<Vec<_>>();
let key_len = sp_std::mem::size_of::<<T::Hashing as sp_runtime::traits::Hash>::Output>();
let key_bytes = keys.iter().flatten().cloned().collect::<Vec<_>>();
let key_bytes_len = key_bytes.len();
let code = WasmModule::<T>::from(ModuleDefinition {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "__unstable__",
name: "seal_take_storage",
params: vec![ValueType::I32, ValueType::I32, ValueType::I32],
return_type: Some(ValueType::I32),
}],
data_segments: vec![
DataSegment {
offset: 0,
value: key_bytes,
},
DataSegment {
offset: key_bytes_len as u32,
value: T::Schedule::get().limits.payload_len.to_le_bytes().into(),
},
],
call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![
Counter(0, key_len as u32), // key_ptr
Regular(Instruction::I32Const((key_bytes_len + 4) as i32)), // out_ptr
Regular(Instruction::I32Const(key_bytes_len as i32)), // out_len_ptr
Regular(Instruction::Call(0)),
Regular(Instruction::Drop),
])),
.. Default::default()
});
let instance = Contract::<T>::new(code, vec![])?;
let info = instance.info()?;
for key in keys {
Storage::<T>::write(
&info.trie_id,
key.as_slice().try_into().map_err(|e| "Key has wrong length")?,
Some(vec![]),
None,
false,
)
.map_err(|_| "Failed to write to storage during setup.")?;
}
<ContractInfoOf<T>>::insert(&instance.account_id, info.clone());
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])

#[skip_meta]
seal_take_storage_per_kb {
let n in 0 .. T::Schedule::get().limits.payload_len / 1024;
let keys = (0 .. API_BENCHMARK_BATCH_SIZE)
.map(|n| T::Hashing::hash_of(&n).as_ref().to_vec())
.collect::<Vec<_>>();
let key_len = sp_std::mem::size_of::<<T::Hashing as sp_runtime::traits::Hash>::Output>();
let key_bytes = keys.iter().flatten().cloned().collect::<Vec<_>>();
let key_bytes_len = key_bytes.len();
let code = WasmModule::<T>::from(ModuleDefinition {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "__unstable__",
name: "seal_take_storage",
params: vec![ValueType::I32, ValueType::I32, ValueType::I32],
return_type: Some(ValueType::I32),
}],
data_segments: vec![
DataSegment {
offset: 0,
value: key_bytes,
},
DataSegment {
offset: key_bytes_len as u32,
value: T::Schedule::get().limits.payload_len.to_le_bytes().into(),
},
],
call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![
Counter(0, key_len as u32), // key_ptr
Regular(Instruction::I32Const((key_bytes_len + 4) as i32)), // out_ptr
Regular(Instruction::I32Const(key_bytes_len as i32)), // out_len_ptr
Regular(Instruction::Call(0)),
Regular(Instruction::Drop),
])),
.. Default::default()
});
let instance = Contract::<T>::new(code, vec![])?;
let info = instance.info()?;
for key in keys {
Storage::<T>::write(
&info.trie_id,
key.as_slice().try_into().map_err(|e| "Key has wrong length")?,
Some(vec![42u8; (n * 1024) as usize]),
None,
false,
)
.map_err(|_| "Failed to write to storage during setup.")?;
}
<ContractInfoOf<T>>::insert(&instance.account_id, info.clone());
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])

// We transfer to unique accounts.
seal_transfer {
let r in 0 .. API_BENCHMARK_BATCHES;
Expand Down Expand Up @@ -2285,7 +2446,7 @@ benchmarks! {
// configured `Schedule` during benchmark development.
// It can be outputed using the following command:
// cargo run --manifest-path=bin/node/cli/Cargo.toml --release \
// --features runtime-benchmarks -- benchmark --dev --execution=native \
// --features runtime-benchmarks -- benchmark --extra --dev --execution=native \
// -p pallet_contracts -e print_schedule --no-median-slopes --no-min-squares
#[extra]
print_schedule {
Expand Down
Loading

0 comments on commit f831307

Please sign in to comment.