mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 07:01:05 +00:00
srml-contract: update ext_random(_seed) (#2635)
* Initial implementation. * Rename random_seed to random * Update rustdocs * Update COMPLEXITY.md * Fix comment. * Limit the size of subject. * Bump the runtime version. * Fix doc * Update node/runtime/src/lib.rs Co-Authored-By: thiolliere <gui.thiolliere@gmail.com>
This commit is contained in:
committed by
Gavin Wood
parent
b017e683dc
commit
12f052ce9d
@@ -298,11 +298,13 @@ This function serializes the address of the caller into the scratch buffer.
|
||||
|
||||
**complexity**: Assuming that the address is of constant size, this function has constant complexity.
|
||||
|
||||
## ext_random_seed
|
||||
## ext_random
|
||||
|
||||
This function serializes the current block's random seed into the scratch buffer.
|
||||
This function serializes a random number generated by the given subject into the scratch buffer.
|
||||
The complexity of this function highly depends on the complexity of `System::random`. `max_subject_len`
|
||||
limits the size of the subject buffer.
|
||||
|
||||
**complexity**: Assuming that the random seed is of constant size, this function has constant complexity.
|
||||
**complexity**: The complexity of this function depends on the implementation of `System::random`.
|
||||
|
||||
## ext_now
|
||||
|
||||
|
||||
@@ -106,8 +106,8 @@ pub trait Ext {
|
||||
/// Returns a reference to the timestamp of the current block
|
||||
fn now(&self) -> &MomentOf<Self::T>;
|
||||
|
||||
/// Returns a reference to the random seed for the current block
|
||||
fn random_seed(&self) -> &SeedOf<Self::T>;
|
||||
/// Returns a random number for the current block with the given subject.
|
||||
fn random(&self, subject: &[u8]) -> SeedOf<Self::T>;
|
||||
|
||||
/// Deposit an event with the given topics.
|
||||
///
|
||||
@@ -353,7 +353,6 @@ where
|
||||
caller: self.self_account.clone(),
|
||||
value_transferred: value,
|
||||
timestamp: timestamp::Module::<T>::now(),
|
||||
random_seed: system::Module::<T>::random_seed(),
|
||||
},
|
||||
input_data,
|
||||
empty_output_buf,
|
||||
@@ -423,7 +422,6 @@ where
|
||||
caller: self.self_account.clone(),
|
||||
value_transferred: endowment,
|
||||
timestamp: timestamp::Module::<T>::now(),
|
||||
random_seed: system::Module::<T>::random_seed(),
|
||||
},
|
||||
input_data,
|
||||
EmptyOutputBuf::new(),
|
||||
@@ -576,7 +574,6 @@ struct CallContext<'a, 'b: 'a, T: Trait + 'b, V: Vm<T> + 'b, L: Loader<T>> {
|
||||
caller: T::AccountId,
|
||||
value_transferred: BalanceOf<T>,
|
||||
timestamp: T::Moment,
|
||||
random_seed: T::Hash,
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a, T, E, V, L> Ext for CallContext<'a, 'b, T, V, L>
|
||||
@@ -642,8 +639,8 @@ where
|
||||
self.value_transferred
|
||||
}
|
||||
|
||||
fn random_seed(&self) -> &T::Hash {
|
||||
&self.random_seed
|
||||
fn random(&self, subject: &[u8]) -> SeedOf<T> {
|
||||
system::Module::<T>::random(subject)
|
||||
}
|
||||
|
||||
fn now(&self) -> &T::Moment {
|
||||
|
||||
@@ -690,6 +690,9 @@ pub struct Schedule<Gas> {
|
||||
/// Whether the `ext_println` function is allowed to be used contracts.
|
||||
/// MUST only be enabled for `dev` chains, NOT for production chains
|
||||
pub enable_println: bool,
|
||||
|
||||
/// The maximum length of a subject used for PRNG generation.
|
||||
pub max_subject_len: u32,
|
||||
}
|
||||
|
||||
impl<Gas: From<u32>> Default for Schedule<Gas> {
|
||||
@@ -709,6 +712,7 @@ impl<Gas: From<u32>> Default for Schedule<Gas> {
|
||||
max_stack_height: 64 * 1024,
|
||||
max_memory_pages: 16,
|
||||
enable_println: false,
|
||||
max_subject_len: 32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,9 +177,10 @@ mod tests {
|
||||
use crate::exec::{CallReceipt, Ext, InstantiateReceipt, EmptyOutputBuf, StorageKey};
|
||||
use crate::gas::GasMeter;
|
||||
use crate::tests::{Test, Call};
|
||||
use wabt;
|
||||
use crate::wasm::prepare::prepare_contract;
|
||||
use crate::CodeHash;
|
||||
use wabt;
|
||||
use hex_literal::hex;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct DispatchEntry(Call);
|
||||
@@ -207,7 +208,6 @@ mod tests {
|
||||
// (topics, data)
|
||||
events: Vec<(Vec<H256>, Vec<u8>)>,
|
||||
next_account_id: u64,
|
||||
random_seed: H256,
|
||||
}
|
||||
impl Ext for MockExt {
|
||||
type T = Test;
|
||||
@@ -276,8 +276,8 @@ mod tests {
|
||||
&1111
|
||||
}
|
||||
|
||||
fn random_seed(&self) -> &H256{
|
||||
&self.random_seed
|
||||
fn random(&self, subject: &[u8]) -> H256 {
|
||||
H256::from_slice(subject)
|
||||
}
|
||||
|
||||
fn deposit_event(&mut self, topics: Vec<H256>, data: Vec<u8>) {
|
||||
@@ -1115,11 +1115,12 @@ mod tests {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
const CODE_RANDOM_SEED: &str = r#"
|
||||
const CODE_RANDOM: &str = r#"
|
||||
(module
|
||||
(import "env" "ext_random_seed" (func $ext_random_seed))
|
||||
(import "env" "ext_random" (func $ext_random (param i32 i32)))
|
||||
(import "env" "ext_scratch_size" (func $ext_scratch_size (result i32)))
|
||||
(import "env" "ext_scratch_copy" (func $ext_scratch_copy (param i32 i32 i32)))
|
||||
(import "env" "ext_return" (func $ext_return (param i32 i32)))
|
||||
(import "env" "memory" (memory 1 1))
|
||||
|
||||
(func $assert (param i32)
|
||||
@@ -1133,7 +1134,10 @@ mod tests {
|
||||
|
||||
(func (export "call")
|
||||
;; This stores the block random seed in the scratch buffer
|
||||
(call $ext_random_seed)
|
||||
(call $ext_random
|
||||
(i32.const 40) ;; Pointer in memory to the start of the subject buffer
|
||||
(i32.const 32) ;; The subject buffer's length
|
||||
)
|
||||
|
||||
;; assert $ext_scratch_size == 32
|
||||
(call $assert
|
||||
@@ -1150,35 +1154,44 @@ mod tests {
|
||||
(i32.const 32) ;; Count of bytes to copy.
|
||||
)
|
||||
|
||||
;; assert the contents of the buffer in 4 x i64 parts matches 1,2,3,4.
|
||||
(call $assert (i64.eq (i64.load (i32.const 8)) (i64.const 1)))
|
||||
(call $assert (i64.eq (i64.load (i32.const 16)) (i64.const 2)))
|
||||
(call $assert (i64.eq (i64.load (i32.const 24)) (i64.const 3)))
|
||||
(call $assert (i64.eq (i64.load (i32.const 32)) (i64.const 4)))
|
||||
;; return the data from the contract
|
||||
(call $ext_return
|
||||
(i32.const 8)
|
||||
(i32.const 32)
|
||||
)
|
||||
)
|
||||
(func (export "deploy"))
|
||||
|
||||
;; [8,40) is reserved for the result of PRNG.
|
||||
|
||||
;; the subject used for the PRNG. [40,72)
|
||||
(data (i32.const 40)
|
||||
"\00\01\02\03\04\05\06\07\08\09\0A\0B\0C\0D\0E\0F"
|
||||
"\00\01\02\03\04\05\06\07\08\09\0A\0B\0C\0D\0E\0F"
|
||||
)
|
||||
)
|
||||
"#;
|
||||
|
||||
#[test]
|
||||
fn random_seed() {
|
||||
fn random() {
|
||||
let mut mock_ext = MockExt::default();
|
||||
let seed: [u8; 32] = [
|
||||
1,0,0,0,0,0,0,0,
|
||||
2,0,0,0,0,0,0,0,
|
||||
3,0,0,0,0,0,0,0,
|
||||
4,0,0,0,0,0,0,0,
|
||||
];
|
||||
mock_ext.random_seed = H256::from_slice(&seed);
|
||||
let mut gas_meter = GasMeter::with_limit(50_000, 1);
|
||||
|
||||
let mut return_buf = Vec::new();
|
||||
execute(
|
||||
CODE_RANDOM_SEED,
|
||||
CODE_RANDOM,
|
||||
&[],
|
||||
&mut Vec::new(),
|
||||
&mut return_buf,
|
||||
&mut mock_ext,
|
||||
&mut gas_meter,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// The mock ext just returns the same data that was passed as the subject.
|
||||
assert_eq!(
|
||||
&return_buf,
|
||||
&hex!("000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F")
|
||||
);
|
||||
}
|
||||
|
||||
const CODE_DEPOSIT_EVENT: &str = r#"
|
||||
|
||||
@@ -527,9 +527,19 @@ define_env!(Env, <E: Ext>,
|
||||
Ok(())
|
||||
},
|
||||
|
||||
// Load the latest block RNG seed into the scratch buffer
|
||||
ext_random_seed(ctx) => {
|
||||
ctx.scratch_buf = ctx.ext.random_seed().encode();
|
||||
// Stores the random number for the current block for the given subject into the scratch
|
||||
// buffer.
|
||||
//
|
||||
// The data is encoded as T::Hash. The current contents of the scratch buffer are
|
||||
// overwritten.
|
||||
ext_random(ctx, subject_ptr: u32, subject_len: u32) => {
|
||||
// The length of a subject can't exceed `max_subject_len`.
|
||||
if subject_len > ctx.schedule.max_subject_len {
|
||||
return Err(sandbox::HostError);
|
||||
}
|
||||
|
||||
let subject_buf = read_sandbox_memory(ctx, subject_ptr, subject_len)?;
|
||||
ctx.scratch_buf = ctx.ext.random(&subject_buf).encode();
|
||||
Ok(())
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user