From 295a3a1b3a07e34230bded736a7a3a4ed59af3be Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Mon, 7 Aug 2023 15:23:30 +0800 Subject: [PATCH 01/89] Module Read & Write intersection and seq fallback --- Cargo.lock | 1 + vm/parallel-executor/Cargo.toml | 1 + vm/parallel-executor/src/errors.rs | 12 ++- vm/parallel-executor/src/executor.rs | 92 +++++++++++++------ .../src/proptest_types/bencher.rs | 13 ++- .../src/proptest_types/tests.rs | 80 +++++++++++++--- .../src/proptest_types/types.rs | 50 ++++++++-- vm/parallel-executor/src/task.rs | 18 +++- .../src/txn_last_input_output.rs | 53 ++++++++++- vm/types/src/access_path.rs | 4 + vm/types/src/unit_tests/access_path_test.rs | 1 + vm/vm-runtime/src/parallel_executor/mod.rs | 3 +- vm/vm-runtime/src/starcoin_vm.rs | 7 +- 13 files changed, 271 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 76d53a4e80..f9e8584e13 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10275,6 +10275,7 @@ dependencies = [ "starcoin-infallible", "starcoin-logger", "starcoin-mvhashmap", + "starcoin-vm-types", ] [[package]] diff --git a/vm/parallel-executor/Cargo.toml b/vm/parallel-executor/Cargo.toml index 6162bc58de..88fb17beaf 100644 --- a/vm/parallel-executor/Cargo.toml +++ b/vm/parallel-executor/Cargo.toml @@ -25,6 +25,7 @@ starcoin-logger = { workspace = true } criterion = { workspace = true, optional = true } proptest = { workspace = true, optional = true } proptest-derive = { workspace = true, optional = true } +starcoin-vm-types = { workspace = true } [dev-dependencies] criterion = { workspace = true } diff --git a/vm/parallel-executor/src/errors.rs b/vm/parallel-executor/src/errors.rs index 4b6c357296..b9a9a8934c 100644 --- a/vm/parallel-executor/src/errors.rs +++ b/vm/parallel-executor/src/errors.rs @@ -1,16 +1,22 @@ // Copyright (c) The Starcoin Core Contributors // SPDX-License-Identifier: Apache-2.0 -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum Error { /// Invariant violation that happens internally inside of scheduler, usually an indication of /// implementation error. InvariantViolation, + /// The same module access path for module was both read & written during speculative executions. + /// This may trigger a race due to the Move-VM loader cache implementation, and mitigation requires + /// aborting the parallel execution pipeline and falling back to the sequential execution. + /// TODO: (short-med term) relax the limitation, and (mid-long term) provide proper multi-versioning + /// for code (like data) for the cache. + ModulePathReadWrite, + /// This may trigger the parallel execution when txn output in Block trigger UpgradeEvent or ConfigChangeEvent + BlockRestart, /// Execution of a thread yields a non-recoverable error, such error will be propagated back to /// the caller. UserError(E), - - BlockRestart, } pub type Result = ::std::result::Result>; diff --git a/vm/parallel-executor/src/executor.rs b/vm/parallel-executor/src/executor.rs index 17f69c91cd..b03ff79ac2 100644 --- a/vm/parallel-executor/src/executor.rs +++ b/vm/parallel-executor/src/executor.rs @@ -5,14 +5,23 @@ use crate::errors::Error::BlockRestart; use crate::{ errors::*, scheduler::{Scheduler, SchedulerTask, TaskGuard, TxnIndex, Version}, - task::{ExecutionStatus, ExecutorTask, Transaction, TransactionOutput}, + task::{ExecutionStatus, ExecutorTask, ModulePath, Transaction, TransactionOutput}, txn_last_input_output::{ReadDescriptor, TxnLastInputOutput}, }; use num_cpus; use once_cell::sync::Lazy; use starcoin_infallible::Mutex; use starcoin_mvhashmap::MVHashMap; -use std::{collections::HashSet, hash::Hash, marker::PhantomData, sync::Arc, thread::spawn}; +use std::{ + collections::HashSet, + hash::Hash, + marker::PhantomData, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, + thread::spawn, +}; static RAYON_EXEC_POOL: Lazy = Lazy::new(|| { rayon::ThreadPoolBuilder::new() @@ -36,7 +45,9 @@ pub struct MVHashMapView<'a, K, V> { captured_reads: Mutex>>, } -impl<'a, K: PartialOrd + Send + Clone + Hash + Eq, V: Send + Sync> MVHashMapView<'a, K, V> { +impl<'a, K: ModulePath + PartialOrd + Send + Clone + Hash + Eq, V: Send + Sync> + MVHashMapView<'a, K, V> +{ /// Drains the captured reads. pub fn take_reads(&self) -> Vec> { let mut reads = self.captured_reads.lock(); @@ -138,7 +149,7 @@ where versioned_data_cache: &MVHashMap<::Key, ::Value>, scheduler: &'a Scheduler, executor: &E, - ) -> SchedulerTask<'a> { + ) -> anyhow::Result> { let (idx_to_execute, incarnation) = version; let txn = &signature_verified_block[idx_to_execute]; @@ -191,8 +202,8 @@ where versioned_data_cache.delete(k, idx_to_execute); } - last_input_output.record(idx_to_execute, state_view.take_reads(), result); - scheduler.finish_execution(idx_to_execute, incarnation, writes_outside, guard) + last_input_output.record(idx_to_execute, state_view.take_reads(), result)?; + Ok(scheduler.finish_execution(idx_to_execute, incarnation, writes_outside, guard)) } fn validate<'a>( @@ -245,12 +256,16 @@ where >, versioned_data_cache: &MVHashMap<::Key, ::Value>, scheduler: &Scheduler, + module_publish_may_race: &AtomicBool, ) { // Make executor for each task. TODO: fast concurrent executor. let executor = E::init(*executor_arguments); let mut scheduler_task = SchedulerTask::NoTask; loop { + if module_publish_may_race.load(Ordering::Acquire) { + break; + } scheduler_task = match scheduler_task { SchedulerTask::ValidationTask(version_to_validate, guard) => self.validate( version_to_validate, @@ -259,15 +274,23 @@ where versioned_data_cache, scheduler, ), - SchedulerTask::ExecutionTask(version_to_execute, None, guard) => self.execute( - version_to_execute, - guard, - block, - last_input_output, - versioned_data_cache, - scheduler, - &executor, - ), + SchedulerTask::ExecutionTask(version_to_execute, None, guard) => { + match self.execute( + version_to_execute, + guard, + block, + last_input_output, + versioned_data_cache, + scheduler, + &executor, + ) { + Ok(task) => task, + Err(_) => { + module_publish_may_race.store(true, Ordering::Release); + break; + } + } + } SchedulerTask::ExecutionTask(_, Some(condvar), _guard) => { let (lock, cvar) = &*condvar; // Mark dependency resolved. @@ -298,6 +321,7 @@ where let versioned_data_cache = MVHashMap::new(); let last_input_output = TxnLastInputOutput::new(num_txns); let scheduler = Scheduler::new(num_txns); + let module_publish_may_race = AtomicBool::new(false); RAYON_EXEC_POOL.scope(|s| { for _ in 0..self.concurrency_level { @@ -308,28 +332,36 @@ where &last_input_output, &versioned_data_cache, &scheduler, + &module_publish_may_race, ); }); } }); // TODO: for large block sizes and many cores, extract outputs in parallel. - let mut maybe_err = None; - let mut final_results = Vec::with_capacity(num_txns); let num_txns = scheduler.num_txn_to_execute(); - for idx in 0..num_txns { - match last_input_output.take_output(idx) { - ExecutionStatus::Success(t) => final_results.push(t), - ExecutionStatus::SkipRest(_t) => { - maybe_err = Some(BlockRestart); - break; - } - ExecutionStatus::Abort(err) => { - maybe_err = Some(err); - break; - } - }; - } + let mut final_results = Vec::with_capacity(num_txns); + let maybe_err = if module_publish_may_race.load(Ordering::Acquire) { + Some(Error::ModulePathReadWrite) + } else { + let mut ret = None; + for idx in 0..num_txns { + match last_input_output.take_output(idx) { + ExecutionStatus::Success(t) => final_results.push(t), + ExecutionStatus::SkipRest(_t) => { + // info!("SkipRest idx {} num_txns {}", idx, num_txns); + // final_results.push(t); + ret = Some(BlockRestart); + break; + } + ExecutionStatus::Abort(err) => { + ret = Some(err); + break; + } + }; + } + ret + }; spawn(move || { // Explicit async drops. diff --git a/vm/parallel-executor/src/proptest_types/bencher.rs b/vm/parallel-executor/src/proptest_types/bencher.rs index 82fecb4a65..49c14f0da9 100644 --- a/vm/parallel-executor/src/proptest_types/bencher.rs +++ b/vm/parallel-executor/src/proptest_types/bencher.rs @@ -17,6 +17,7 @@ use proptest::{ test_runner::TestRunner, }; +use crate::proptest_types::types::KeyType; use std::{fmt::Debug, hash::Hash, marker::PhantomData}; pub struct Bencher { @@ -27,8 +28,8 @@ pub struct Bencher { phantom_value: PhantomData, } -pub(crate) struct BencherState { - transactions: Vec>, +pub(crate) struct BencherState { + transactions: Vec, V>>, expected_output: ExpectedOutput, } @@ -91,7 +92,7 @@ where let transactions: Vec<_> = transaction_gens .into_iter() - .map(|txn_gen| txn_gen.materialize(&key_universe)) + .map(|txn_gen| txn_gen.materialize(&key_universe, (false, false))) .collect(); let expected_output = ExpectedOutput::generate_baseline(&transactions); @@ -104,8 +105,10 @@ where pub(crate) fn run(self) { let output = - ParallelTransactionExecutor::, Task>::new(num_cpus::get()) - .execute_transactions_parallel((), self.transactions.clone()); + ParallelTransactionExecutor::, V>, Task, V>>::new( + num_cpus::get(), + ) + .execute_transactions_parallel((), self.transactions.clone()); assert!(self.expected_output.check_output(&output)); } diff --git a/vm/parallel-executor/src/proptest_types/tests.rs b/vm/parallel-executor/src/proptest_types/tests.rs index fefe427b6c..896af4be59 100644 --- a/vm/parallel-executor/src/proptest_types/tests.rs +++ b/vm/parallel-executor/src/proptest_types/tests.rs @@ -1,6 +1,8 @@ // Copyright (c) Starcoin // SPDX-License-Identifier: Apache-2.0 +use crate::errors::Error; +use crate::proptest_types::types::KeyType; use crate::{ executor::ParallelTransactionExecutor, proptest_types::types::{ @@ -18,11 +20,12 @@ use proptest::{ use std::{fmt::Debug, hash::Hash}; fn run_transactions( - key_universe: Vec, + key_universe: &[K], transaction_gens: Vec>, abort_transactions: Vec, skip_rest_transactions: Vec, num_repeat: usize, + module_access: (bool, bool), ) -> bool where K: Hash + Clone + Debug + Eq + Send + Sync + PartialOrd + Ord + 'static, @@ -30,7 +33,7 @@ where { let mut transactions: Vec<_> = transaction_gens .into_iter() - .map(|txn_gen| txn_gen.materialize(&key_universe)) + .map(|txn_gen| txn_gen.materialize(key_universe, module_access)) .collect(); let length = transactions.len(); @@ -46,8 +49,15 @@ where let mut ret = true; for _ in 0..num_repeat { let output = - ParallelTransactionExecutor::, Task>::new(num_cpus::get()) - .execute_transactions_parallel((), transactions.clone()); + ParallelTransactionExecutor::, V>, Task, V>>::new( + num_cpus::get(), + ) + .execute_transactions_parallel((), transactions.clone()); + + if module_access.0 && module_access.1 { + assert_eq!(output.unwrap_err(), Error::ModulePathReadWrite); + continue; + } let baseline = ExpectedOutput::generate_baseline(&transactions); @@ -65,7 +75,7 @@ proptest! { abort_transactions in vec(any::(), 0), skip_rest_transactions in vec(any::(), 0), ) { - prop_assert!(run_transactions(universe, transaction_gen, abort_transactions, skip_rest_transactions, 1)); + prop_assert!(run_transactions(&universe, transaction_gen, abort_transactions, skip_rest_transactions, 1, (false,false))); } #[test] @@ -75,7 +85,7 @@ proptest! { abort_transactions in vec(any::(), 5), skip_rest_transactions in vec(any::(), 0), ) { - prop_assert!(run_transactions(universe, transaction_gen, abort_transactions, skip_rest_transactions, 1)); + prop_assert!(run_transactions(&universe, transaction_gen, abort_transactions, skip_rest_transactions, 1, (false,false))); } #[test] @@ -85,7 +95,7 @@ proptest! { abort_transactions in vec(any::(), 0), skip_rest_transactions in vec(any::(), 5), ) { - prop_assert!(run_transactions(universe, transaction_gen, abort_transactions, skip_rest_transactions, 1)); + prop_assert!(run_transactions(&universe, transaction_gen, abort_transactions, skip_rest_transactions, 1,(false,false))); } #[test] @@ -95,7 +105,7 @@ proptest! { abort_transactions in vec(any::(), 5), skip_rest_transactions in vec(any::(), 5), ) { - prop_assert!(run_transactions(universe, transaction_gen, abort_transactions, skip_rest_transactions, 1)); + prop_assert!(run_transactions(&universe, transaction_gen, abort_transactions, skip_rest_transactions, 1,(false,false))); } #[test] @@ -105,7 +115,7 @@ proptest! { abort_transactions in vec(any::(), 3), skip_rest_transactions in vec(any::(), 3), ) { - prop_assert!(run_transactions(universe, transaction_gen, abort_transactions, skip_rest_transactions, 1)); + prop_assert!(run_transactions(&universe, transaction_gen, abort_transactions, skip_rest_transactions, 1,(false,false))); } } @@ -126,11 +136,12 @@ fn dynamic_read_writes() { .current(); assert!(run_transactions( - universe, + &universe, transaction_gen, vec![], vec![], - 100 + 100, + (false, false), )); } @@ -152,10 +163,53 @@ fn dynamic_read_writes_contended() { .current(); assert!(run_transactions( - universe, + &universe, + transaction_gen, + vec![], + vec![], + 100, + (false, false), + )); +} + +#[test] +fn module_publishing_fallback() { + let mut runner = TestRunner::default(); + + let universe = vec(any::<[u8; 32]>(), 100) + .new_tree(&mut runner) + .expect("creating a new value should succeed") + .current(); + let transaction_gen = vec( + any_with::>(TransactionGenParams::new_dynamic()), + 3000, + ) + .new_tree(&mut runner) + .expect("creating a new value should succeed") + .current(); + + assert!(run_transactions( + &universe, + transaction_gen.clone(), + vec![], + vec![], + 2, + (false, true), + )); + assert!(run_transactions( + &universe, + transaction_gen.clone(), + vec![], + vec![], + 2, + (false, true), + )); + assert!(run_transactions( + &universe, transaction_gen, vec![], vec![], - 100 + 2, + (true, true), )); } diff --git a/vm/parallel-executor/src/proptest_types/types.rs b/vm/parallel-executor/src/proptest_types/types.rs index 58ee7e49c2..9ceb567feb 100644 --- a/vm/parallel-executor/src/proptest_types/types.rs +++ b/vm/parallel-executor/src/proptest_types/types.rs @@ -4,10 +4,13 @@ use crate::{ errors::{Error, Result}, executor::MVHashMapView, + task::ModulePath, task::{ExecutionStatus, ExecutorTask, Transaction as TransactionType, TransactionOutput}, }; use proptest::{arbitrary::Arbitrary, collection::vec, prelude::*, proptest, sample::Index}; use proptest_derive::Arbitrary; +use starcoin_vm_types::identifier::Identifier; +use starcoin_vm_types::{access_path::AccessPath, account_address::AccountAddress}; use std::{ collections::{BTreeSet, HashMap}, fmt::Debug, @@ -19,10 +22,35 @@ use std::{ }, }; +impl ModulePath for KeyType { + fn module_path(&self) -> Option { + if self.1 { + Some(AccessPath { + address: AccountAddress::new([1u8; AccountAddress::LENGTH]), + // XXX FIXME YSG CONFIRM + path: AccessPath::code_data_path(Identifier::new("foo").unwrap()), + }) + } else { + None + } + } +} + /////////////////////////////////////////////////////////////////////////// // Generation of transactions /////////////////////////////////////////////////////////////////////////// +#[derive(Clone, Copy, Hash, Debug, PartialEq, PartialOrd, Eq)] +pub struct KeyType( + /// Wrapping the types used for testing to add ModulePath trait implementation (below). + pub K, + /// The bool field determines for testing purposes, whether the key will be interpreted + /// as a module access path. In this case, if a module path is both read and written + /// during parallel execution, Error::ModulePathReadWrite must be returned and the + /// block execution must fall back to the sequential execution. + pub bool, +); + #[derive(Clone, Copy)] pub struct TransactionGenParams { /// Each transaction's write-set consists of between 1 and write_size-1 many writes. @@ -96,17 +124,22 @@ impl Default for TransactionGenParams { } impl TransactionGen { - pub fn materialize(self, universe: &[K]) -> Transaction { + pub fn materialize( + self, + universe: &[K], + // Are writes and reads module access (same access path). + module_access: (bool, bool), + ) -> Transaction, V> { let mut keys_modified = BTreeSet::new(); let mut writes = vec![]; for modified in self.keys_modified.into_iter() { - let mut incarnation_writes: Vec<(K, V)> = vec![]; + let mut incarnation_writes: Vec<(KeyType, V)> = vec![]; for (idx, value) in modified.into_iter() { let key = universe[idx.index(universe.len())].clone(); if !keys_modified.contains(&key) { keys_modified.insert(key.clone()); - incarnation_writes.push((key, value.clone())); + incarnation_writes.push((KeyType(key, module_access.0), value.clone())); } } writes.push(incarnation_writes); @@ -121,7 +154,9 @@ impl TransactionGen { .map(|keys_read| { keys_read .into_iter() - .map(|k| universe[k.index(universe.len())].clone()) + .map(|k| { + KeyType(universe[k.index(universe.len())].clone(), module_access.1) + }) .collect() }) .collect(), @@ -131,7 +166,7 @@ impl TransactionGen { impl TransactionType for Transaction where - K: PartialOrd + Send + Sync + Clone + Hash + Eq + 'static, + K: PartialOrd + Send + Sync + Clone + Hash + Eq + ModulePath + 'static, V: Send + Sync + Debug + Clone + 'static, { type Key = K; @@ -152,7 +187,7 @@ impl Task { impl ExecutorTask for Task where - K: PartialOrd + Send + Sync + Clone + Hash + Eq + 'static, + K: PartialOrd + Send + Sync + Clone + Hash + Eq + ModulePath + 'static, V: Send + Sync + Debug + Clone + 'static, { type T = Transaction; @@ -196,11 +231,12 @@ where } } +#[derive(Debug)] pub struct Output(Vec<(K, V)>, Vec>); impl TransactionOutput for Output where - K: PartialOrd + Send + Sync + Clone + Hash + Eq + 'static, + K: PartialOrd + Send + Sync + Clone + Hash + Eq + ModulePath + 'static, V: Send + Sync + Debug + Clone + 'static, { type T = Transaction; diff --git a/vm/parallel-executor/src/task.rs b/vm/parallel-executor/src/task.rs index ae1b2de8fc..1d566347bc 100644 --- a/vm/parallel-executor/src/task.rs +++ b/vm/parallel-executor/src/task.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::executor::MVHashMapView; +use starcoin_vm_types::{access_path::AccessPath, state_store::state_key::StateKey}; use std::{fmt::Debug, hash::Hash}; /// The execution result of a transaction @@ -17,10 +18,25 @@ pub enum ExecutionStatus { SkipRest(T), } +pub trait ModulePath { + fn module_path(&self) -> Option; +} + +impl ModulePath for StateKey { + fn module_path(&self) -> Option { + if let StateKey::AccessPath(ap) = self { + if ap.is_code() { + return Some(ap.clone()); + } + } + None + } +} + /// Trait that defines a transaction that could be parallel executed by the scheduler. Each /// transaction will write to a key value storage as their side effect. pub trait Transaction: Sync + Send + 'static { - type Key: PartialOrd + Send + Sync + Clone + Hash + Eq; + type Key: PartialOrd + Send + Sync + Clone + Hash + Eq + ModulePath; type Value: Send + Sync; } diff --git a/vm/parallel-executor/src/txn_last_input_output.rs b/vm/parallel-executor/src/txn_last_input_output.rs index 19baa8a700..a4bc5b21fe 100644 --- a/vm/parallel-executor/src/txn_last_input_output.rs +++ b/vm/parallel-executor/src/txn_last_input_output.rs @@ -1,13 +1,17 @@ // Copyright (c) The Starcoin Core Contributors // SPDX-License-Identifier: Apache-2.0 +use crate::task::ModulePath; use crate::{ errors::Error, scheduler::{Incarnation, TxnIndex, Version}, task::{ExecutionStatus, Transaction, TransactionOutput}, }; +use anyhow::{bail, Result}; use arc_swap::ArcSwapOption; use crossbeam::utils::CachePadded; +use dashmap::DashSet; +use starcoin_vm_types::access_path::AccessPath; use std::{collections::HashSet, sync::Arc}; type TxnInput = Vec>; @@ -30,7 +34,7 @@ pub struct ReadDescriptor { kind: ReadKind, } -impl ReadDescriptor { +impl ReadDescriptor { pub fn from(access_path: K, txn_idx: TxnIndex, incarnation: Incarnation) -> Self { Self { access_path, @@ -45,6 +49,10 @@ impl ReadDescriptor { } } + fn module_path(&self) -> Option { + self.access_path.module_path() + } + pub fn path(&self) -> &K { &self.access_path } @@ -65,9 +73,15 @@ pub struct TxnLastInputOutput { inputs: Vec>>>, // txn_idx -> input. outputs: Vec>>>, // txn_idx -> output. + + // Record all writes and reads to access paths corresponding to modules (code) in any + // (speculative) executions. Used to avoid a potential race with module publishing and + // Move-VM loader cache - see 'record' function comment for more information. + module_writes: DashSet, + module_reads: DashSet, } -impl TxnLastInputOutput { +impl TxnLastInputOutput { pub fn new(num_txns: usize) -> Self { Self { inputs: (0..num_txns) @@ -76,17 +90,50 @@ impl TxnLastInputOutput { outputs: (0..num_txns) .map(|_| CachePadded::new(ArcSwapOption::empty())) .collect(), + module_writes: DashSet::new(), + module_reads: DashSet::new(), } } + fn append_and_check( + paths: Vec, + set_to_append: &DashSet, + set_to_check: &DashSet, + ) -> Result<()> { + for path in paths { + // Standard flags, first show, then look. + set_to_append.insert(path.clone()); + + if set_to_check.contains(&path) { + bail!("Module published and also read"); + } + } + Ok(()) + } + pub fn record( &self, txn_idx: TxnIndex, input: Vec>, output: ExecutionStatus>, - ) { + ) -> Result<()> { + let read_modules: Vec = + input.iter().filter_map(|desc| desc.module_path()).collect(); + let written_modules: Vec = match &output { + ExecutionStatus::Success(output) | ExecutionStatus::SkipRest(output) => output + .get_writes() + .into_iter() + .filter_map(|(k, _)| k.module_path()) + .collect(), + ExecutionStatus::Abort(_) => Vec::new(), + }; + + Self::append_and_check(read_modules, &self.module_reads, &self.module_writes)?; + Self::append_and_check(written_modules, &self.module_writes, &self.module_reads)?; + self.inputs[txn_idx].store(Some(Arc::new(input))); self.outputs[txn_idx].store(Some(Arc::new(output))); + Ok(()) } pub fn read_set(&self, txn_idx: TxnIndex) -> Option>>> { diff --git a/vm/types/src/access_path.rs b/vm/types/src/access_path.rs index fa559a2f32..0a30be3c93 100644 --- a/vm/types/src/access_path.rs +++ b/vm/types/src/access_path.rs @@ -113,6 +113,10 @@ impl AccessPath { _ => None, } } + + pub fn is_code(&self) -> bool { + self.path.is_code() + } } impl Serialize for AccessPath { diff --git a/vm/types/src/unit_tests/access_path_test.rs b/vm/types/src/unit_tests/access_path_test.rs index 807a43c4a7..c0bca72c1b 100644 --- a/vm/types/src/unit_tests/access_path_test.rs +++ b/vm/types/src/unit_tests/access_path_test.rs @@ -26,6 +26,7 @@ fn test_access_path_str_valid() { r1.as_str()]; for case in test_cases { let access_path = AccessPath::from_str(case).unwrap(); + println!("access {}", access_path); assert_eq!(case.to_owned(), access_path.to_string()) } } diff --git a/vm/vm-runtime/src/parallel_executor/mod.rs b/vm/vm-runtime/src/parallel_executor/mod.rs index d63740a717..0aad3f93d4 100644 --- a/vm/vm-runtime/src/parallel_executor/mod.rs +++ b/vm/vm-runtime/src/parallel_executor/mod.rs @@ -88,7 +88,8 @@ impl ParallelStarcoinVM { .collect(), None, )), - Err(err @ Error::BlockRestart) => { + // XXX FIXME YSG + Err(err @ Error::BlockRestart) | Err(err @ Error::ModulePathReadWrite) => { let output = StarcoinVM::execute_block_and_keep_vm_status( transactions, state_view, diff --git a/vm/vm-runtime/src/starcoin_vm.rs b/vm/vm-runtime/src/starcoin_vm.rs index c9402e5f51..79ca404747 100644 --- a/vm/vm-runtime/src/starcoin_vm.rs +++ b/vm/vm-runtime/src/starcoin_vm.rs @@ -1041,6 +1041,8 @@ impl StarcoinVM { state_view: &S, output: &TransactionOutput, ) -> Result<(), Error> { + // XXX FIXME YSG if GasSchedule.move UpgradeEvent + // XXX FIXME YSG ConfigChangeEvent include ConsensusConfig, DaoConfig,GasScheule, MoveLanguageVersion, TransactionPublishOption, VMConfig for event in output.events() { if event.key().get_creator_address() == genesis_address() && (event.is::() || event.is::>()) @@ -1516,7 +1518,7 @@ impl VMExecutor for StarcoinVM { ) -> Result, VMStatus> { let concurrency_level = Self::get_concurrency_level(); if concurrency_level > 1 { - let (result, _) = crate::parallel_executor::ParallelStarcoinVM::execute_block( + let (result, err) = crate::parallel_executor::ParallelStarcoinVM::execute_block( transactions, state_view, concurrency_level, @@ -1524,6 +1526,7 @@ impl VMExecutor for StarcoinVM { metrics, )?; // debug!("TurboSTM executor concurrency_level {}", concurrency_level); + debug!("Parallel execution error {:?}", err); Ok(result) } else { let output = Self::execute_block_and_keep_vm_status( @@ -1555,6 +1558,8 @@ impl VMAdapter for StarcoinVM { fn should_restart_execution(output: &TransactionOutput) -> bool { // XXX FIXME YSG if GasSchedule.move UpgradeEvent + // XXX FIXME YSG ConfigChangeEvent include ConsensusConfig, DaoConfig,GasScheule, MoveLanguageVersion, TransactionPublishOption, VMConfig + for event in output.events() { if event.key().get_creator_address() == genesis_address() && (event.is::() || event.is::>()) From b2338e268813e0107aeb954dac3ebe69ae4aca6a Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Mon, 7 Aug 2023 15:44:16 +0800 Subject: [PATCH 02/89] add Module detection --- vm/parallel-executor/src/executor.rs | 51 +++++-------------- .../src/txn_last_input_output.rs | 36 +++++++++---- 2 files changed, 41 insertions(+), 46 deletions(-) diff --git a/vm/parallel-executor/src/executor.rs b/vm/parallel-executor/src/executor.rs index b03ff79ac2..e54fe0147d 100644 --- a/vm/parallel-executor/src/executor.rs +++ b/vm/parallel-executor/src/executor.rs @@ -12,16 +12,7 @@ use num_cpus; use once_cell::sync::Lazy; use starcoin_infallible::Mutex; use starcoin_mvhashmap::MVHashMap; -use std::{ - collections::HashSet, - hash::Hash, - marker::PhantomData, - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, - }, - thread::spawn, -}; +use std::{collections::HashSet, hash::Hash, marker::PhantomData, sync::Arc, thread::spawn}; static RAYON_EXEC_POOL: Lazy = Lazy::new(|| { rayon::ThreadPoolBuilder::new() @@ -149,7 +140,7 @@ where versioned_data_cache: &MVHashMap<::Key, ::Value>, scheduler: &'a Scheduler, executor: &E, - ) -> anyhow::Result> { + ) -> SchedulerTask<'a> { let (idx_to_execute, incarnation) = version; let txn = &signature_verified_block[idx_to_execute]; @@ -202,8 +193,8 @@ where versioned_data_cache.delete(k, idx_to_execute); } - last_input_output.record(idx_to_execute, state_view.take_reads(), result)?; - Ok(scheduler.finish_execution(idx_to_execute, incarnation, writes_outside, guard)) + last_input_output.record(idx_to_execute, state_view.take_reads(), result); + scheduler.finish_execution(idx_to_execute, incarnation, writes_outside, guard) } fn validate<'a>( @@ -256,16 +247,12 @@ where >, versioned_data_cache: &MVHashMap<::Key, ::Value>, scheduler: &Scheduler, - module_publish_may_race: &AtomicBool, ) { // Make executor for each task. TODO: fast concurrent executor. let executor = E::init(*executor_arguments); let mut scheduler_task = SchedulerTask::NoTask; loop { - if module_publish_may_race.load(Ordering::Acquire) { - break; - } scheduler_task = match scheduler_task { SchedulerTask::ValidationTask(version_to_validate, guard) => self.validate( version_to_validate, @@ -274,23 +261,15 @@ where versioned_data_cache, scheduler, ), - SchedulerTask::ExecutionTask(version_to_execute, None, guard) => { - match self.execute( - version_to_execute, - guard, - block, - last_input_output, - versioned_data_cache, - scheduler, - &executor, - ) { - Ok(task) => task, - Err(_) => { - module_publish_may_race.store(true, Ordering::Release); - break; - } - } - } + SchedulerTask::ExecutionTask(version_to_execute, None, guard) => self.execute( + version_to_execute, + guard, + block, + last_input_output, + versioned_data_cache, + scheduler, + &executor, + ), SchedulerTask::ExecutionTask(_, Some(condvar), _guard) => { let (lock, cvar) = &*condvar; // Mark dependency resolved. @@ -321,7 +300,6 @@ where let versioned_data_cache = MVHashMap::new(); let last_input_output = TxnLastInputOutput::new(num_txns); let scheduler = Scheduler::new(num_txns); - let module_publish_may_race = AtomicBool::new(false); RAYON_EXEC_POOL.scope(|s| { for _ in 0..self.concurrency_level { @@ -332,7 +310,6 @@ where &last_input_output, &versioned_data_cache, &scheduler, - &module_publish_may_race, ); }); } @@ -341,7 +318,7 @@ where // TODO: for large block sizes and many cores, extract outputs in parallel. let num_txns = scheduler.num_txn_to_execute(); let mut final_results = Vec::with_capacity(num_txns); - let maybe_err = if module_publish_may_race.load(Ordering::Acquire) { + let maybe_err = if last_input_output.module_publishing_may_race() { Some(Error::ModulePathReadWrite) } else { let mut ret = None; diff --git a/vm/parallel-executor/src/txn_last_input_output.rs b/vm/parallel-executor/src/txn_last_input_output.rs index a4bc5b21fe..e69c238f2d 100644 --- a/vm/parallel-executor/src/txn_last_input_output.rs +++ b/vm/parallel-executor/src/txn_last_input_output.rs @@ -7,12 +7,17 @@ use crate::{ scheduler::{Incarnation, TxnIndex, Version}, task::{ExecutionStatus, Transaction, TransactionOutput}, }; -use anyhow::{bail, Result}; use arc_swap::ArcSwapOption; use crossbeam::utils::CachePadded; use dashmap::DashSet; use starcoin_vm_types::access_path::AccessPath; -use std::{collections::HashSet, sync::Arc}; +use std::{ + collections::HashSet, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, +}; type TxnInput = Vec>; type TxnOutput = ExecutionStatus>; @@ -79,6 +84,8 @@ pub struct TxnLastInputOutput { // Move-VM loader cache - see 'record' function comment for more information. module_writes: DashSet, module_reads: DashSet, + + module_read_write_intersection: AtomicBool, } impl TxnLastInputOutput { @@ -92,6 +99,7 @@ impl TxnLastInputOutput TxnLastInputOutput, set_to_append: &DashSet, set_to_check: &DashSet, - ) -> Result<()> { + ) -> bool { for path in paths { // Standard flags, first show, then look. set_to_append.insert(path.clone()); if set_to_check.contains(&path) { - bail!("Module published and also read"); + return true; } } - Ok(()) + false } pub fn record( @@ -116,7 +124,7 @@ impl TxnLastInputOutput>, output: ExecutionStatus>, - ) -> Result<()> { + ) { let read_modules: Vec = input.iter().filter_map(|desc| desc.module_path()).collect(); let written_modules: Vec = match &output { @@ -128,12 +136,22 @@ impl TxnLastInputOutput Vec::new(), }; - Self::append_and_check(read_modules, &self.module_reads, &self.module_writes)?; - Self::append_and_check(written_modules, &self.module_writes, &self.module_reads)?; + if !self.module_read_write_intersection.load(Ordering::Relaxed) { + // Check if adding new read & write modules leads to intersections. + if Self::append_and_check(read_modules, &self.module_reads, &self.module_writes) + || Self::append_and_check(written_modules, &self.module_writes, &self.module_reads) + { + self.module_read_write_intersection + .store(true, Ordering::Release); + } + } self.inputs[txn_idx].store(Some(Arc::new(input))); self.outputs[txn_idx].store(Some(Arc::new(output))); - Ok(()) + } + + pub fn module_publishing_may_race(&self) -> bool { + self.module_read_write_intersection.load(Ordering::Acquire) } pub fn read_set(&self, txn_idx: TxnIndex) -> Option>>> { From 2972b810b4c4d7d29047778772cece6b56ba3325 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Mon, 7 Aug 2023 18:58:21 +0800 Subject: [PATCH 03/89] [Parallel Execution] Combinatorial test to check module intersection --- Cargo.lock | 6 +- vm/mvhashmap/Cargo.toml | 2 +- vm/parallel-executor/Cargo.toml | 2 +- .../src/proptest_types/tests.rs | 109 ++++++++++++++++++ .../src/proptest_types/types.rs | 102 +++++++++++----- vm/proptest-helpers/Cargo.toml | 2 +- 6 files changed, 189 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9e8584e13..97363d3ae2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10008,7 +10008,7 @@ dependencies = [ [[package]] name = "starcoin-mvhashmap" -version = "1.13.4" +version = "1.13.5" dependencies = [ "arc-swap", "crossbeam", @@ -10260,7 +10260,7 @@ dependencies = [ [[package]] name = "starcoin-parallel-executor" -version = "1.13.4" +version = "1.13.5" dependencies = [ "anyhow", "arc-swap", @@ -10301,7 +10301,7 @@ dependencies = [ [[package]] name = "starcoin-proptest-helpers" -version = "1.13.4" +version = "1.13.5" dependencies = [ "crossbeam", "proptest", diff --git a/vm/mvhashmap/Cargo.toml b/vm/mvhashmap/Cargo.toml index 1e6353ed85..1c061e5eab 100644 --- a/vm/mvhashmap/Cargo.toml +++ b/vm/mvhashmap/Cargo.toml @@ -5,7 +5,7 @@ edition = { workspace = true } license = { workspace = true } name = "starcoin-mvhashmap" publish = { workspace = true } -version = "1.13.4" +version = "1.13.5" homepage = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } diff --git a/vm/parallel-executor/Cargo.toml b/vm/parallel-executor/Cargo.toml index 88fb17beaf..8ed4b296b0 100644 --- a/vm/parallel-executor/Cargo.toml +++ b/vm/parallel-executor/Cargo.toml @@ -5,7 +5,7 @@ edition = { workspace = true } license = { workspace = true } name = "starcoin-parallel-executor" publish = { workspace = true } -version = "1.13.4" +version = "1.13.5" homepage = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } diff --git a/vm/parallel-executor/src/proptest_types/tests.rs b/vm/parallel-executor/src/proptest_types/tests.rs index 896af4be59..d19ec69e68 100644 --- a/vm/parallel-executor/src/proptest_types/tests.rs +++ b/vm/parallel-executor/src/proptest_types/tests.rs @@ -213,3 +213,112 @@ fn module_publishing_fallback() { (true, true), )); } + +fn publishing_fixed_params() { + let mut runner = TestRunner::default(); + let num_txns = 300; + + let universe = vec(any::<[u8; 32]>(), 50) + .new_tree(&mut runner) + .expect("creating a new value should succeed") + .current(); + let transaction_gen = vec( + any_with::>(TransactionGenParams::new_dynamic()), + num_txns, + ) + .new_tree(&mut runner) + .expect("creating a new value should succeed") + .current(); + let indices = vec(any::(), 4) + .new_tree(&mut runner) + .expect("creating a new value should succeed") + .current(); + + // First 12 keys are normal paths, next 14 are module reads, then writes. + let mut transactions: Vec<_> = transaction_gen + .into_iter() + .map(|txn_gen| txn_gen.materialize_disjoint_module_rw(&universe[0..40], 12, 26)) + .collect(); + + // Adjust the writes of txn indices[0] to contain module write to key 42. + let w_index = indices[0].index(num_txns); + *transactions.get_mut(w_index).unwrap() = match transactions.get_mut(w_index).unwrap() { + Transaction::Write { + incarnation, + reads, + writes, + } => { + let mut new_writes = vec![]; + for incarnation_writes in writes { + assert!(!incarnation_writes.is_empty()); + let val = incarnation_writes[0].1; + let insert_idx = indices[1].index(incarnation_writes.len()); + incarnation_writes.insert(insert_idx, (KeyType(universe[42], true), val)); + new_writes.push(incarnation_writes.clone()); + } + + Transaction::Write { + incarnation: incarnation.clone(), + reads: reads.clone(), + writes: new_writes, + } + } + _ => { + unreachable!(); + } + }; + + // Confirm still no intersection + let output = ParallelTransactionExecutor::< + Transaction, [u8; 32]>, + Task, [u8; 32]>, + >::new(num_cpus::get()) + .execute_transactions_parallel((), transactions.clone()); + assert!(output.is_ok()); + + // Adjust the reads of txn indices[2] to contain module read to key 42. + let r_index = indices[2].index(num_txns); + *transactions.get_mut(r_index).unwrap() = match transactions.get_mut(r_index).unwrap() { + Transaction::Write { + incarnation, + reads, + writes, + } => { + let mut new_reads = vec![]; + for incarnation_reads in reads { + assert!(!incarnation_reads.is_empty()); + let insert_idx = indices[3].index(incarnation_reads.len()); + incarnation_reads.insert(insert_idx, KeyType(universe[42], true)); + new_reads.push(incarnation_reads.clone()); + } + + Transaction::Write { + incarnation: incarnation.clone(), + reads: new_reads, + writes: writes.clone(), + } + } + _ => { + unreachable!(); + } + }; + + for _ in 0..200 { + let output = ParallelTransactionExecutor::< + Transaction, [u8; 32]>, + Task, [u8; 32]>, + >::new(num_cpus::get()) + .execute_transactions_parallel((), transactions.clone()); + + assert_eq!(output.unwrap_err(), Error::ModulePathReadWrite); + } +} + +#[test] +// Test a single transaction intersection interleaves with a lot of dependencies and +// not overlapping module r/w keys. +fn module_publishing_races() { + for _ in 0..10 { + publishing_fixed_params(); + } +} diff --git a/vm/parallel-executor/src/proptest_types/types.rs b/vm/parallel-executor/src/proptest_types/types.rs index 9ceb567feb..b62833d38c 100644 --- a/vm/parallel-executor/src/proptest_types/types.rs +++ b/vm/parallel-executor/src/proptest_types/types.rs @@ -11,10 +11,11 @@ use proptest::{arbitrary::Arbitrary, collection::vec, prelude::*, proptest, samp use proptest_derive::Arbitrary; use starcoin_vm_types::identifier::Identifier; use starcoin_vm_types::{access_path::AccessPath, account_address::AccountAddress}; +use std::collections::hash_map::DefaultHasher; use std::{ collections::{BTreeSet, HashMap}, fmt::Debug, - hash::Hash, + hash::{Hash, Hasher}, marker::PhantomData, sync::{ atomic::{AtomicUsize, Ordering}, @@ -24,9 +25,14 @@ use std::{ impl ModulePath for KeyType { fn module_path(&self) -> Option { + // Since K is generic, use its hash to assign addresses. + let mut hasher = DefaultHasher::new(); + self.0.hash(&mut hasher); + let mut hashed_address = vec![1u8; AccountAddress::LENGTH - 8]; + hashed_address.extend_from_slice(&hasher.finish().to_ne_bytes()); if self.1 { Some(AccessPath { - address: AccountAddress::new([1u8; AccountAddress::LENGTH]), + address: AccountAddress::new(hashed_address.try_into().unwrap()), // XXX FIXME YSG CONFIRM path: AccessPath::code_data_path(Identifier::new("foo").unwrap()), }) @@ -124,42 +130,82 @@ impl Default for TransactionGenParams { } impl TransactionGen { - pub fn materialize( - self, + fn writes_from_gen( universe: &[K], - // Are writes and reads module access (same access path). - module_access: (bool, bool), - ) -> Transaction, V> { - let mut keys_modified = BTreeSet::new(); - let mut writes = vec![]; - - for modified in self.keys_modified.into_iter() { + gen: Vec>, + module_write_fn: &dyn Fn(usize) -> bool, + ) -> Vec, V)>> { + let mut ret = vec![]; + for write_gen in gen.into_iter() { + let mut keys_modified = BTreeSet::new(); let mut incarnation_writes: Vec<(KeyType, V)> = vec![]; - for (idx, value) in modified.into_iter() { - let key = universe[idx.index(universe.len())].clone(); + for (idx, value) in write_gen.into_iter() { + let i = idx.index(universe.len()); + let key = universe[i].clone(); if !keys_modified.contains(&key) { keys_modified.insert(key.clone()); - incarnation_writes.push((KeyType(key, module_access.0), value.clone())); + incarnation_writes.push((KeyType(key, module_write_fn(i)), value.clone())); } } - writes.push(incarnation_writes); + ret.push(incarnation_writes); + } + ret + } + + fn reads_from_gen( + universe: &[K], + gen: Vec>, + module_read_fn: &dyn Fn(usize) -> bool, + ) -> Vec>> { + let mut ret = vec![]; + for read_gen in gen.into_iter() { + let mut incarnation_reads: Vec> = vec![]; + for idx in read_gen.into_iter() { + let i = idx.index(universe.len()); + let key = universe[i].clone(); + incarnation_reads.push(KeyType(key, module_read_fn(i))); + } + ret.push(incarnation_reads); + } + ret + } + + pub fn materialize( + self, + universe: &[K], + // Are writes and reads module access (same access path). + module_access: (bool, bool), + ) -> Transaction, V> { + Transaction::Write { + incarnation: Arc::new(AtomicUsize::new(0)), + writes: Self::writes_from_gen(universe, self.keys_modified, &|_| -> bool { + module_access.0 + }), + reads: Self::reads_from_gen(universe, self.keys_read, &|_| -> bool { module_access.1 }), } + } + + pub fn materialize_disjoint_module_rw( + self, + universe: &[K], + // keys generated with indices from read_threshold to write_threshold will be + // treated as module access only in reads. keys generated with indices from + // write threshold to universe.len() will be treated as module access only in + // writes. This way there will be module accesses but no intersection. + read_threshold: usize, + write_threshold: usize, + ) -> Transaction, V> { + assert!(read_threshold < universe.len()); + assert!(write_threshold > read_threshold); + assert!(write_threshold < universe.len()); + + let is_module_write = |i| -> bool { i >= write_threshold }; + let is_module_read = |i| -> bool { i >= read_threshold && i < write_threshold }; Transaction::Write { incarnation: Arc::new(AtomicUsize::new(0)), - writes, - reads: self - .keys_read - .into_iter() - .map(|keys_read| { - keys_read - .into_iter() - .map(|k| { - KeyType(universe[k.index(universe.len())].clone(), module_access.1) - }) - .collect() - }) - .collect(), + writes: Self::writes_from_gen(universe, self.keys_modified, &is_module_write), + reads: Self::reads_from_gen(universe, self.keys_read, &is_module_read), } } } diff --git a/vm/proptest-helpers/Cargo.toml b/vm/proptest-helpers/Cargo.toml index a1e50bf64e..70ee92ab82 100644 --- a/vm/proptest-helpers/Cargo.toml +++ b/vm/proptest-helpers/Cargo.toml @@ -4,7 +4,7 @@ authors = { workspace = true } edition = { workspace = true } license = { workspace = true } publish = { workspace = true } -version = "1.13.4" +version = "1.13.5" homepage = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } From eea3bd8ddbf0326faa89e3f946bfba390441127c Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Mon, 14 Aug 2023 16:29:42 +0800 Subject: [PATCH 04/89] rename parallel-executor to block-executor --- Cargo.lock | 44 ++++----- Cargo.toml | 8 +- executor/src/block_executor.rs | 8 +- scripts/benchmark_parallel.sh | 2 +- .../Cargo.toml | 4 +- .../benches/scheduler_benches.rs | 0 .../src/errors.rs | 0 .../src/executor.rs | 8 +- .../src/lib.rs | 0 .../src/proptest_types/bencher.rs | 8 +- .../src/proptest_types/mod.rs | 0 .../src/proptest_types/tests.rs | 12 +-- .../src/proptest_types/types.rs | 0 .../src/scheduler.rs | 0 .../src/task.rs | 0 .../src/txn_last_input_output.rs | 0 vm/e2e-tests/Cargo.toml | 2 +- vm/e2e-tests/src/executor.rs | 2 +- vm/vm-runtime/Cargo.toml | 2 +- vm/vm-runtime/src/adapter_common.rs | 2 +- .../mod.rs | 19 ++-- .../storage_wrapper.rs | 2 +- .../vm_wrapper.rs | 4 +- vm/vm-runtime/src/data_cache.rs | 8 +- vm/vm-runtime/src/errors.rs | 8 +- vm/vm-runtime/src/lib.rs | 2 +- vm/vm-runtime/src/move_vm_ext/session.rs | 36 +++---- vm/vm-runtime/src/move_vm_ext/vm.rs | 13 +-- vm/vm-runtime/src/natives.rs | 7 +- vm/vm-runtime/src/starcoin_vm.rs | 94 +++++++++---------- 30 files changed, 147 insertions(+), 148 deletions(-) rename vm/{parallel-executor => block-executor}/Cargo.toml (89%) rename vm/{parallel-executor => block-executor}/benches/scheduler_benches.rs (100%) rename vm/{parallel-executor => block-executor}/src/errors.rs (100%) rename vm/{parallel-executor => block-executor}/src/executor.rs (98%) rename vm/{parallel-executor => block-executor}/src/lib.rs (100%) rename vm/{parallel-executor => block-executor}/src/proptest_types/bencher.rs (92%) rename vm/{parallel-executor => block-executor}/src/proptest_types/mod.rs (100%) rename vm/{parallel-executor => block-executor}/src/proptest_types/tests.rs (96%) rename vm/{parallel-executor => block-executor}/src/proptest_types/types.rs (100%) rename vm/{parallel-executor => block-executor}/src/scheduler.rs (100%) rename vm/{parallel-executor => block-executor}/src/task.rs (100%) rename vm/{parallel-executor => block-executor}/src/txn_last_input_output.rs (100%) rename vm/vm-runtime/src/{parallel_executor => block_executor}/mod.rs (87%) rename vm/vm-runtime/src/{parallel_executor => block_executor}/storage_wrapper.rs (95%) rename vm/vm-runtime/src/{parallel_executor => block_executor}/vm_wrapper.rs (95%) diff --git a/Cargo.lock b/Cargo.lock index 97363d3ae2..f91825e35a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9219,6 +9219,26 @@ dependencies = [ "starcoin-logger", ] +[[package]] +name = "starcoin-block-executor" +version = "1.13.5" +dependencies = [ + "anyhow", + "arc-swap", + "criterion", + "crossbeam", + "dashmap", + "num_cpus", + "once_cell", + "proptest", + "proptest-derive", + "rayon", + "starcoin-infallible", + "starcoin-logger", + "starcoin-mvhashmap", + "starcoin-vm-types", +] + [[package]] name = "starcoin-block-relayer" version = "1.13.7" @@ -9802,11 +9822,11 @@ dependencies = [ "proptest-derive", "rand 0.8.5", "serde 1.0.152", + "starcoin-block-executor", "starcoin-config", "starcoin-crypto", "starcoin-gas", "starcoin-gas-algebra-ext", - "starcoin-parallel-executor", "starcoin-proptest-helpers", "starcoin-state-tree", "starcoin-statedb", @@ -10258,26 +10278,6 @@ dependencies = [ "stest", ] -[[package]] -name = "starcoin-parallel-executor" -version = "1.13.5" -dependencies = [ - "anyhow", - "arc-swap", - "criterion", - "crossbeam", - "dashmap", - "num_cpus", - "once_cell", - "proptest", - "proptest-derive", - "rayon", - "starcoin-infallible", - "starcoin-logger", - "starcoin-mvhashmap", - "starcoin-vm-types", -] - [[package]] name = "starcoin-peer-watcher" version = "1.13.7" @@ -11013,6 +11013,7 @@ dependencies = [ "rand_core 0.6.4", "rayon", "serde 1.0.152", + "starcoin-block-executor", "starcoin-config", "starcoin-crypto", "starcoin-gas", @@ -11020,7 +11021,6 @@ dependencies = [ "starcoin-logger", "starcoin-metrics", "starcoin-natives", - "starcoin-parallel-executor", "starcoin-types", "starcoin-vm-types", "stdlib", diff --git a/Cargo.toml b/Cargo.toml index d8cee9cb41..d4f6ecf1de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,7 +75,7 @@ members = [ "vm/compiler", "vm/move-prover", "vm/mvhashmap", - "vm/parallel-executor", + "vm/block-executor", "vm/transaction-builder", "vm/transaction-builder-generator", "vm/move-coverage", @@ -87,7 +87,7 @@ members = [ "vm/move-package-manager", "vm/vm-status-translator", "vm/starcoin-transactional-test-harness", - "vm/parallel-executor", + "vm/block-executor", "vm/transaction-benchmarks", "vm/e2e-tests", "vm/proptest-helpers", @@ -185,7 +185,7 @@ default-members = [ "vm/compiler", "vm/move-prover", "vm/mvhashmap", - "vm/parallel-executor", + "vm/block-executor", "vm/transaction-builder", "vm/transaction-builder-generator", "vm/move-coverage", @@ -492,7 +492,7 @@ stest-macro = { path = "commons/stest/stest-macro" } stream-task = { path = "commons/stream-task" } starcoin-mvhashmap = { path = "vm/mvhashmap" } starcoin-infallible = { path = "commons/infallible" } -starcoin-parallel-executor = { path = "vm/parallel-executor" } +starcoin-block-executor = { path = "vm/block-executor" } starcoin-transaction-benchmarks = { path = "vm/transaction-benchmarks" } starcoin-language-e2e-tests = { path = "vm/e2e-tests" } starcoin-proptest-helpers = { path = "vm/proptest-helpers" } diff --git a/executor/src/block_executor.rs b/executor/src/block_executor.rs index 32af240a4e..a70278a46f 100644 --- a/executor/src/block_executor.rs +++ b/executor/src/block_executor.rs @@ -3,10 +3,10 @@ use starcoin_crypto::HashValue; use starcoin_state_api::{ChainStateReader, ChainStateWriter}; -use starcoin_types::error::BlockExecutorError; -use starcoin_types::error::ExecutorResult; -use starcoin_types::transaction::TransactionStatus; -use starcoin_types::transaction::{Transaction, TransactionInfo}; +use starcoin_types::{ + error::{BlockExecutorError, ExecutorResult}, + transaction::{Transaction, TransactionInfo, TransactionStatus}, +}; use starcoin_vm_runtime::metrics::VMMetrics; use starcoin_vm_types::contract_event::ContractEvent; use starcoin_vm_types::state_store::table::{TableHandle, TableInfo}; diff --git a/scripts/benchmark_parallel.sh b/scripts/benchmark_parallel.sh index 98755dca18..7b18eb66e4 100755 --- a/scripts/benchmark_parallel.sh +++ b/scripts/benchmark_parallel.sh @@ -1,2 +1,2 @@ -RUST_LOG=info cargo bench --features fuzzing -p 'starcoin-parallel-executor' +RUST_LOG=info cargo bench --features fuzzing -p 'starcoin-block-executor' RUST_LOG=info cargo bench --features fuzzing -p 'starcoin-transaction-benchmarks' \ No newline at end of file diff --git a/vm/parallel-executor/Cargo.toml b/vm/block-executor/Cargo.toml similarity index 89% rename from vm/parallel-executor/Cargo.toml rename to vm/block-executor/Cargo.toml index 8ed4b296b0..277de7df4f 100644 --- a/vm/parallel-executor/Cargo.toml +++ b/vm/block-executor/Cargo.toml @@ -1,9 +1,9 @@ [package] authors = { workspace = true } -description = "Starcoin parallel transaction executor library" +description = "Starcoin block transaction executor library, parallel execution via Turbo-STM" edition = { workspace = true } license = { workspace = true } -name = "starcoin-parallel-executor" +name = "starcoin-block-executor" publish = { workspace = true } version = "1.13.5" homepage = { workspace = true } diff --git a/vm/parallel-executor/benches/scheduler_benches.rs b/vm/block-executor/benches/scheduler_benches.rs similarity index 100% rename from vm/parallel-executor/benches/scheduler_benches.rs rename to vm/block-executor/benches/scheduler_benches.rs diff --git a/vm/parallel-executor/src/errors.rs b/vm/block-executor/src/errors.rs similarity index 100% rename from vm/parallel-executor/src/errors.rs rename to vm/block-executor/src/errors.rs diff --git a/vm/parallel-executor/src/executor.rs b/vm/block-executor/src/executor.rs similarity index 98% rename from vm/parallel-executor/src/executor.rs rename to vm/block-executor/src/executor.rs index e54fe0147d..e6f16f0017 100644 --- a/vm/parallel-executor/src/executor.rs +++ b/vm/block-executor/src/executor.rs @@ -17,7 +17,7 @@ use std::{collections::HashSet, hash::Hash, marker::PhantomData, sync::Arc, thre static RAYON_EXEC_POOL: Lazy = Lazy::new(|| { rayon::ThreadPoolBuilder::new() .num_threads(num_cpus::get()) - .thread_name(|index| format!("parallel_executor_{}", index)) + .thread_name(|index| format!("par_exec_{}", index)) .build() .unwrap() }); @@ -68,7 +68,7 @@ impl<'a, K: ModulePath + PartialOrd + Send + Clone + Hash + Eq, V: Send + Sync> // `self.txn_idx` estimated to depend on a write from `dep_idx`. match self.scheduler.wait_for_dependency(self.txn_idx, dep_idx) { Some(dep_condition) => { - // Wait on a condition variable correpsonding to the encountered + // Wait on a condition variable corresponding to the encountered // read dependency. Once the dep_idx finishes re-execution, scheduler // will mark the dependency as resolved, and then the txn_idx will be // scheduled for re-execution, which will re-awaken cvar here. @@ -101,14 +101,14 @@ impl<'a, K: ModulePath + PartialOrd + Send + Clone + Hash + Eq, V: Send + Sync> } } -pub struct ParallelTransactionExecutor { +pub struct BlockExecutor { // number of active concurrent tasks, corresponding to the maximum number of rayon // threads that may be concurrently participating in parallel execution. concurrency_level: usize, phantom: PhantomData<(T, E)>, } -impl ParallelTransactionExecutor +impl BlockExecutor where T: Transaction, E: ExecutorTask, diff --git a/vm/parallel-executor/src/lib.rs b/vm/block-executor/src/lib.rs similarity index 100% rename from vm/parallel-executor/src/lib.rs rename to vm/block-executor/src/lib.rs diff --git a/vm/parallel-executor/src/proptest_types/bencher.rs b/vm/block-executor/src/proptest_types/bencher.rs similarity index 92% rename from vm/parallel-executor/src/proptest_types/bencher.rs rename to vm/block-executor/src/proptest_types/bencher.rs index 49c14f0da9..92e2ddd62d 100644 --- a/vm/parallel-executor/src/proptest_types/bencher.rs +++ b/vm/block-executor/src/proptest_types/bencher.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{ - executor::ParallelTransactionExecutor, + executor::BlockExecutor, proptest_types::types::{ ExpectedOutput, Task, Transaction, TransactionGen, TransactionGenParams, }, @@ -105,10 +105,8 @@ where pub(crate) fn run(self) { let output = - ParallelTransactionExecutor::, V>, Task, V>>::new( - num_cpus::get(), - ) - .execute_transactions_parallel((), self.transactions.clone()); + BlockExecutor::, V>, Task, V>>::new(num_cpus::get()) + .execute_transactions_parallel((), self.transactions.clone()); assert!(self.expected_output.check_output(&output)); } diff --git a/vm/parallel-executor/src/proptest_types/mod.rs b/vm/block-executor/src/proptest_types/mod.rs similarity index 100% rename from vm/parallel-executor/src/proptest_types/mod.rs rename to vm/block-executor/src/proptest_types/mod.rs diff --git a/vm/parallel-executor/src/proptest_types/tests.rs b/vm/block-executor/src/proptest_types/tests.rs similarity index 96% rename from vm/parallel-executor/src/proptest_types/tests.rs rename to vm/block-executor/src/proptest_types/tests.rs index d19ec69e68..10bd08b113 100644 --- a/vm/parallel-executor/src/proptest_types/tests.rs +++ b/vm/block-executor/src/proptest_types/tests.rs @@ -4,7 +4,7 @@ use crate::errors::Error; use crate::proptest_types::types::KeyType; use crate::{ - executor::ParallelTransactionExecutor, + executor::BlockExecutor, proptest_types::types::{ ExpectedOutput, Task, Transaction, TransactionGen, TransactionGenParams, }, @@ -49,10 +49,8 @@ where let mut ret = true; for _ in 0..num_repeat { let output = - ParallelTransactionExecutor::, V>, Task, V>>::new( - num_cpus::get(), - ) - .execute_transactions_parallel((), transactions.clone()); + BlockExecutor::, V>, Task, V>>::new(num_cpus::get()) + .execute_transactions_parallel((), transactions.clone()); if module_access.0 && module_access.1 { assert_eq!(output.unwrap_err(), Error::ModulePathReadWrite); @@ -269,7 +267,7 @@ fn publishing_fixed_params() { }; // Confirm still no intersection - let output = ParallelTransactionExecutor::< + let output = BlockExecutor::< Transaction, [u8; 32]>, Task, [u8; 32]>, >::new(num_cpus::get()) @@ -304,7 +302,7 @@ fn publishing_fixed_params() { }; for _ in 0..200 { - let output = ParallelTransactionExecutor::< + let output = BlockExecutor::< Transaction, [u8; 32]>, Task, [u8; 32]>, >::new(num_cpus::get()) diff --git a/vm/parallel-executor/src/proptest_types/types.rs b/vm/block-executor/src/proptest_types/types.rs similarity index 100% rename from vm/parallel-executor/src/proptest_types/types.rs rename to vm/block-executor/src/proptest_types/types.rs diff --git a/vm/parallel-executor/src/scheduler.rs b/vm/block-executor/src/scheduler.rs similarity index 100% rename from vm/parallel-executor/src/scheduler.rs rename to vm/block-executor/src/scheduler.rs diff --git a/vm/parallel-executor/src/task.rs b/vm/block-executor/src/task.rs similarity index 100% rename from vm/parallel-executor/src/task.rs rename to vm/block-executor/src/task.rs diff --git a/vm/parallel-executor/src/txn_last_input_output.rs b/vm/block-executor/src/txn_last_input_output.rs similarity index 100% rename from vm/parallel-executor/src/txn_last_input_output.rs rename to vm/block-executor/src/txn_last_input_output.rs diff --git a/vm/e2e-tests/Cargo.toml b/vm/e2e-tests/Cargo.toml index 5e9797088d..4ff76c0272 100644 --- a/vm/e2e-tests/Cargo.toml +++ b/vm/e2e-tests/Cargo.toml @@ -31,7 +31,7 @@ starcoin-gas-algebra-ext = { workspace = true } move-core-types = { workspace = true } move-ir-compiler = { workspace = true } starcoin-transaction-builder = { workspace = true } -starcoin-parallel-executor = { workspace = true } +starcoin-block-executor = { workspace = true } test-helper = { workspace = true } stdlib = { workspace = true } starcoin-gas = { workspace = true } diff --git a/vm/e2e-tests/src/executor.rs b/vm/e2e-tests/src/executor.rs index b0e53b869c..c738257cc4 100644 --- a/vm/e2e-tests/src/executor.rs +++ b/vm/e2e-tests/src/executor.rs @@ -14,9 +14,9 @@ use starcoin_crypto::keygen::KeyGen; use starcoin_crypto::HashValue; use starcoin_gas::{StarcoinGasMeter, StarcoinGasParameters}; use starcoin_gas_algebra_ext::InitialGasSchedule; +use starcoin_vm_runtime::block_executor::BlockStarcoinVM; use starcoin_vm_runtime::data_cache::{AsMoveResolver, RemoteStorage}; use starcoin_vm_runtime::move_vm_ext::{MoveVmExt, SessionId, SessionOutput}; -use starcoin_vm_runtime::parallel_executor::ParallelStarcoinVM; use starcoin_vm_runtime::starcoin_vm::StarcoinVM; use starcoin_vm_runtime::VMExecutor; use starcoin_vm_types::{ diff --git a/vm/vm-runtime/Cargo.toml b/vm/vm-runtime/Cargo.toml index 4cdb2832df..41185ade3f 100644 --- a/vm/vm-runtime/Cargo.toml +++ b/vm/vm-runtime/Cargo.toml @@ -31,7 +31,7 @@ starcoin-metrics = { optional = true, workspace = true } starcoin-gas = { workspace = true } starcoin-gas-algebra-ext = { workspace = true } serde = { features = ["derive"], workspace = true } -starcoin-parallel-executor = { workspace = true } +starcoin-block-executor = { workspace = true } rayon = { workspace = true } num_cpus = { workspace = true } diff --git a/vm/vm-runtime/src/adapter_common.rs b/vm/vm-runtime/src/adapter_common.rs index 0186986a97..b16cf84d41 100644 --- a/vm/vm-runtime/src/adapter_common.rs +++ b/vm/vm-runtime/src/adapter_common.rs @@ -5,9 +5,9 @@ use crate::move_vm_ext::{MoveResolverExt, SessionId}; use anyhow::Result; use move_core_types::vm_status::{StatusCode, VMStatus}; use move_vm_runtime::move_vm_adapter::SessionAdapter; -use starcoin_vm_types::state_view::StateView; use starcoin_vm_types::{ block_metadata::BlockMetadata, + state_view::StateView, transaction::{ SignatureCheckedTransaction, SignedUserTransaction, Transaction, TransactionOutput, TransactionStatus, diff --git a/vm/vm-runtime/src/parallel_executor/mod.rs b/vm/vm-runtime/src/block_executor/mod.rs similarity index 87% rename from vm/vm-runtime/src/parallel_executor/mod.rs rename to vm/vm-runtime/src/block_executor/mod.rs index 0aad3f93d4..bb9c29d45a 100644 --- a/vm/vm-runtime/src/parallel_executor/mod.rs +++ b/vm/vm-runtime/src/block_executor/mod.rs @@ -4,17 +4,17 @@ mod storage_wrapper; mod vm_wrapper; -use crate::metrics::VMMetrics; use crate::{ adapter_common::{preprocess_transaction, PreprocessedTransaction}, - parallel_executor::vm_wrapper::StarcoinVMWrapper, + block_executor::vm_wrapper::StarcoinVMWrapper, + metrics::VMMetrics, starcoin_vm::StarcoinVM, }; use move_core_types::vm_status::{StatusCode, VMStatus}; use rayon::prelude::*; -use starcoin_parallel_executor::{ +use starcoin_block_executor::{ errors::Error, - executor::ParallelTransactionExecutor, + executor::BlockExecutor, task::{Transaction as PTransaction, TransactionOutput as PTransactionOutput}, }; use starcoin_vm_types::{ @@ -61,9 +61,9 @@ impl PTransactionOutput for StarcoinTransactionOutput { } } -pub struct ParallelStarcoinVM(); +pub struct BlockStarcoinVM(); -impl ParallelStarcoinVM { +impl BlockStarcoinVM { pub fn execute_block( transactions: Vec, state_view: &S, @@ -76,10 +76,9 @@ impl ParallelStarcoinVM { .map(|txn| preprocess_transaction(txn.clone())) .collect(); - match ParallelTransactionExecutor::>::new( - concurrency_level, - ) - .execute_transactions_parallel(state_view, signature_verified_block) + // XXX FIXME YSG block_gas_limit + match BlockExecutor::>::new(concurrency_level) + .execute_transactions_parallel(state_view, signature_verified_block) { Ok(results) => Ok(( results diff --git a/vm/vm-runtime/src/parallel_executor/storage_wrapper.rs b/vm/vm-runtime/src/block_executor/storage_wrapper.rs similarity index 95% rename from vm/vm-runtime/src/parallel_executor/storage_wrapper.rs rename to vm/vm-runtime/src/block_executor/storage_wrapper.rs index 0a316ac2cc..ee5bdc15cf 100644 --- a/vm/vm-runtime/src/parallel_executor/storage_wrapper.rs +++ b/vm/vm-runtime/src/block_executor/storage_wrapper.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::data_cache::{IntoMoveResolver, RemoteStorageOwned}; -use starcoin_parallel_executor::executor::MVHashMapView; +use starcoin_block_executor::executor::MVHashMapView; use starcoin_vm_types::{ state_store::state_key::StateKey, state_view::StateView, write_set::WriteOp, }; diff --git a/vm/vm-runtime/src/parallel_executor/vm_wrapper.rs b/vm/vm-runtime/src/block_executor/vm_wrapper.rs similarity index 95% rename from vm/vm-runtime/src/parallel_executor/vm_wrapper.rs rename to vm/vm-runtime/src/block_executor/vm_wrapper.rs index 0974cc5964..99039aa08c 100644 --- a/vm/vm-runtime/src/parallel_executor/vm_wrapper.rs +++ b/vm/vm-runtime/src/block_executor/vm_wrapper.rs @@ -3,11 +3,11 @@ use crate::{ adapter_common::{PreprocessedTransaction, VMAdapter}, - parallel_executor::{storage_wrapper::VersionedView, StarcoinTransactionOutput}, + block_executor::{storage_wrapper::VersionedView, StarcoinTransactionOutput}, starcoin_vm::StarcoinVM, }; -use starcoin_parallel_executor::{ +use starcoin_block_executor::{ executor::MVHashMapView, task::{ExecutionStatus, ExecutorTask}, }; diff --git a/vm/vm-runtime/src/data_cache.rs b/vm/vm-runtime/src/data_cache.rs index f380f71410..ddaf1701bf 100644 --- a/vm/vm-runtime/src/data_cache.rs +++ b/vm/vm-runtime/src/data_cache.rs @@ -8,17 +8,19 @@ use move_core_types::resolver::{ModuleResolver, ResourceResolver}; use move_table_extension::{TableHandle, TableResolver}; use starcoin_logger::prelude::*; use starcoin_types::account_address::AccountAddress; -use starcoin_vm_types::state_store::state_key::StateKey; use starcoin_vm_types::{ access_path::AccessPath, errors::*, language_storage::{ModuleId, StructTag}, + state_store::state_key::StateKey, state_view::StateView, vm_status::StatusCode, write_set::{WriteOp, WriteSet}, }; -use std::collections::btree_map::BTreeMap; -use std::ops::{Deref, DerefMut}; +use std::{ + collections::btree_map::BTreeMap, + ops::{Deref, DerefMut}, +}; /// A local cache for a given a `StateView`. The cache is private to the Diem layer /// but can be used as a one shot cache for systems that need a simple `RemoteCache` diff --git a/vm/vm-runtime/src/errors.rs b/vm/vm-runtime/src/errors.rs index 71d6b2ea89..70e7668f4b 100644 --- a/vm/vm-runtime/src/errors.rs +++ b/vm/vm-runtime/src/errors.rs @@ -2,9 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 use starcoin_logger::prelude::*; -use starcoin_vm_types::account_config::G_ACCOUNT_MODULE; -use starcoin_vm_types::errors::VMError; -use starcoin_vm_types::vm_status::{AbortLocation, StatusCode, VMStatus}; +use starcoin_vm_types::{ + account_config::G_ACCOUNT_MODULE, + errors::VMError, + vm_status::{AbortLocation, StatusCode, VMStatus}, +}; //should be consistent with ErrorCode.move const PROLOGUE_ACCOUNT_DOES_NOT_EXIST: u64 = 0; diff --git a/vm/vm-runtime/src/lib.rs b/vm/vm-runtime/src/lib.rs index 2680fefa62..ccb78dfa6f 100644 --- a/vm/vm-runtime/src/lib.rs +++ b/vm/vm-runtime/src/lib.rs @@ -11,9 +11,9 @@ pub mod starcoin_vm; use move_core_types::vm_status::VMStatus; pub use move_vm_runtime::{move_vm, session}; mod access_path_cache; +pub mod block_executor; mod errors; pub mod move_vm_ext; -pub mod parallel_executor; use crate::metrics::VMMetrics; use starcoin_vm_types::{ access_path::AccessPath, diff --git a/vm/vm-runtime/src/move_vm_ext/session.rs b/vm/vm-runtime/src/move_vm_ext/session.rs index 57c3b8aa42..6a78ea101e 100644 --- a/vm/vm-runtime/src/move_vm_ext/session.rs +++ b/vm/vm-runtime/src/move_vm_ext/session.rs @@ -1,23 +1,27 @@ use crate::access_path_cache::AccessPathCache; -use move_core_types::account_address::AccountAddress; -use move_core_types::effects::{ - ChangeSet as MoveChangeSet, Event as MoveEvent, Op as MoveStorageOp, +use move_core_types::{ + account_address::AccountAddress, + effects::{ChangeSet as MoveChangeSet, Event as MoveEvent, Op as MoveStorageOp}, +}; +use move_core_types::{ + language_storage::ModuleId, + vm_status::{StatusCode, VMStatus}, }; -use move_core_types::language_storage::ModuleId; -use move_core_types::vm_status::{StatusCode, VMStatus}; use move_table_extension::TableChangeSet; use serde::{Deserialize, Serialize}; -use starcoin_crypto::hash::{CryptoHash, CryptoHasher, PlainCryptoHash}; -use starcoin_crypto::HashValue; -use starcoin_vm_types::block_metadata::BlockMetadata; -use starcoin_vm_types::contract_event::ContractEvent; -use starcoin_vm_types::event::EventKey; -use starcoin_vm_types::state_store::state_key::StateKey; -use starcoin_vm_types::state_store::table::{TableHandle, TableInfo}; -use starcoin_vm_types::transaction::SignatureCheckedTransaction; -use starcoin_vm_types::transaction_metadata::TransactionMetadata; -use starcoin_vm_types::write_set::{WriteOp, WriteSet, WriteSetMut}; -use std::collections::BTreeMap; +use starcoin_crypto::{ + hash::{CryptoHash, CryptoHasher, PlainCryptoHash}, + HashValue, +}; +use starcoin_vm_types::{ + block_metadata::BlockMetadata, + contract_event::ContractEvent, + event::EventKey, + state_store::state_key::StateKey, + transaction::SignatureCheckedTransaction, + transaction_metadata::TransactionMetadata, + write_set::{WriteOp, WriteSet, WriteSetMut}, +}; use std::convert::TryFrom; #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, CryptoHasher, CryptoHash)] diff --git a/vm/vm-runtime/src/move_vm_ext/vm.rs b/vm/vm-runtime/src/move_vm_ext/vm.rs index bfa8b38b3b..0d31403c3b 100644 --- a/vm/vm-runtime/src/move_vm_ext/vm.rs +++ b/vm/vm-runtime/src/move_vm_ext/vm.rs @@ -1,13 +1,14 @@ // Copyright (c) The Starcoin Core Contributors // SPDX-License-Identifier: Apache-2.0 -use crate::move_vm_ext::session::SessionId; -use crate::move_vm_ext::MoveResolverExt; -use crate::natives; +use crate::{ + move_vm_ext::{session::SessionId, MoveResolverExt}, + natives, +}; use move_table_extension::NativeTableContext; -use move_vm_runtime::move_vm::MoveVM; -use move_vm_runtime::native_extensions::NativeContextExtensions; -use move_vm_runtime::session::Session; +use move_vm_runtime::{ + move_vm::MoveVM, native_extensions::NativeContextExtensions, session::Session, +}; use starcoin_gas::NativeGasParameters; use starcoin_vm_types::errors::{PartialVMResult, VMResult}; use std::ops::Deref; diff --git a/vm/vm-runtime/src/natives.rs b/vm/vm-runtime/src/natives.rs index 3529845f06..af62f6752a 100644 --- a/vm/vm-runtime/src/natives.rs +++ b/vm/vm-runtime/src/natives.rs @@ -1,10 +1,9 @@ // Copyright (c) The Starcoin Core Contributors // SPDX-License-Identifier: Apache-2.0 -use move_core_types::account_address::AccountAddress; -use move_core_types::language_storage::CORE_CODE_ADDRESS; -use move_vm_runtime::native_functions; + +use move_core_types::{account_address::AccountAddress, language_storage::CORE_CODE_ADDRESS}; use move_vm_runtime::native_functions::{ - make_table_from_iter, NativeFunction, NativeFunctionTable, + self, make_table_from_iter, NativeFunction, NativeFunctionTable, }; use starcoin_gas::NativeGasParameters; diff --git a/vm/vm-runtime/src/starcoin_vm.rs b/vm/vm-runtime/src/starcoin_vm.rs index 79ca404747..59e798ab8e 100644 --- a/vm/vm-runtime/src/starcoin_vm.rs +++ b/vm/vm-runtime/src/starcoin_vm.rs @@ -1,20 +1,23 @@ // Copyright (c) The Starcoin Core Contributors // SPDX-License-Identifier: Apache-2.0 -use crate::access_path_cache::AccessPathCache; -use crate::adapter_common::{ - discard_error_output, discard_error_vm_status, PreprocessedTransaction, VMAdapter, -}; -use crate::data_cache::{AsMoveResolver, RemoteStorage, StateViewCache}; -use crate::errors::{ - convert_normal_success_epilogue_error, convert_prologue_runtime_error, error_split, +use crate::{ + access_path_cache::AccessPathCache, + adapter_common::{ + discard_error_output, discard_error_vm_status, PreprocessedTransaction, VMAdapter, + }, + data_cache::{AsMoveResolver, RemoteStorage, StateViewCache}, + errors::{convert_normal_success_epilogue_error, convert_prologue_runtime_error, error_split}, + move_vm_ext::{MoveResolverExt, MoveVmExt, SessionId, SessionOutput}, }; -use crate::move_vm_ext::{MoveResolverExt, MoveVmExt, SessionId, SessionOutput}; use anyhow::{bail, format_err, Error, Result}; use move_core_types::gas_algebra::{InternalGasPerByte, NumBytes}; +use move_core_types::vm_status::StatusCode::STORAGE_ERROR; use move_table_extension::NativeTableContext; -use move_vm_runtime::move_vm_adapter::{PublishModuleBundleOption, SessionAdapter}; -use move_vm_runtime::session::Session; +use move_vm_runtime::{ + move_vm_adapter::{PublishModuleBundleOption, SessionAdapter}, + session::Session, +}; use num_cpus; use once_cell::sync::OnceCell; use starcoin_config::genesis_config::G_LATEST_GAS_PARAMS; @@ -24,51 +27,43 @@ use starcoin_gas_algebra_ext::{ CostTable, FromOnChainGasSchedule, Gas, GasConstants, GasCost, InitialGasSchedule, }; use starcoin_logger::prelude::*; -use starcoin_types::account_config::config_change::ConfigChangeEvent; -use starcoin_types::account_config::{ - access_path_for_module_upgrade_strategy, access_path_for_two_phase_upgrade_v2, -}; use starcoin_types::{ - account_config, + account_config::{ + self, access_path_for_module_upgrade_strategy, access_path_for_two_phase_upgrade_v2, + config_change::ConfigChangeEvent, + }, block_metadata::BlockMetadata, transaction::{ SignatureCheckedTransaction, SignedUserTransaction, Transaction, TransactionOutput, TransactionPayload, TransactionStatus, }, }; -use starcoin_vm_types::access::{ModuleAccess, ScriptAccess}; -use starcoin_vm_types::account_address::AccountAddress; -use starcoin_vm_types::account_config::upgrade::UpgradeEvent; -use starcoin_vm_types::account_config::{ - core_code_address, genesis_address, ModuleUpgradeStrategy, TwoPhaseUpgradeV2Resource, - G_EPILOGUE_NAME, G_EPILOGUE_V2_NAME, G_PROLOGUE_NAME, -}; -use starcoin_vm_types::errors::VMResult; -use starcoin_vm_types::file_format::{CompiledModule, CompiledScript}; -use starcoin_vm_types::gas_schedule::G_LATEST_GAS_COST_TABLE; -use starcoin_vm_types::genesis_config::StdlibVersion; -use starcoin_vm_types::identifier::IdentStr; -use starcoin_vm_types::language_storage::ModuleId; -use starcoin_vm_types::on_chain_config::{ - GasSchedule, MoveLanguageVersion, G_GAS_CONSTANTS_IDENTIFIER, - G_INSTRUCTION_SCHEDULE_IDENTIFIER, G_NATIVE_SCHEDULE_IDENTIFIER, G_VM_CONFIG_IDENTIFIER, -}; -use starcoin_vm_types::state_store::state_key::StateKey; -use starcoin_vm_types::state_view::StateReaderExt; -use starcoin_vm_types::transaction::{DryRunTransaction, Package, TransactionPayloadType}; -use starcoin_vm_types::transaction_metadata::TransactionPayloadMetadata; -use starcoin_vm_types::value::{serialize_values, MoveValue}; -use starcoin_vm_types::vm_status::KeptVMStatus; use starcoin_vm_types::{ - errors::Location, - language_storage::TypeTag, - on_chain_config::{OnChainConfig, VMConfig, Version}, - state_view::StateView, - transaction_metadata::TransactionMetadata, - vm_status::{StatusCode, VMStatus}, + access::{ModuleAccess, ScriptAccess}, + account_address::AccountAddress, + account_config::{ + core_code_address, genesis_address, upgrade::UpgradeEvent, ModuleUpgradeStrategy, + TwoPhaseUpgradeV2Resource, G_EPILOGUE_NAME, G_EPILOGUE_V2_NAME, G_PROLOGUE_NAME, + }, + errors::{Location, VMResult}, + file_format::{CompiledModule, CompiledScript}, + gas_schedule::G_LATEST_GAS_COST_TABLE, + genesis_config::StdlibVersion, + identifier::IdentStr, + language_storage::{ModuleId, TypeTag}, + on_chain_config::{ + GasSchedule, MoveLanguageVersion, OnChainConfig, VMConfig, Version, + G_GAS_CONSTANTS_IDENTIFIER, G_GAS_SCHEDULE_GAS_SCHEDULE, G_GAS_SCHEDULE_IDENTIFIER, + G_INSTRUCTION_SCHEDULE_IDENTIFIER, G_NATIVE_SCHEDULE_IDENTIFIER, G_VM_CONFIG_IDENTIFIER, + }, + state_store::state_key::StateKey, + state_view::{StateReaderExt, StateView}, + transaction::{DryRunTransaction, Package, TransactionPayloadType}, + transaction_metadata::{TransactionMetadata, TransactionPayloadMetadata}, + value::{serialize_values, MoveValue}, + vm_status::{KeptVMStatus, StatusCode, VMStatus}, }; -use std::cmp::min; -use std::sync::Arc; +use std::{cmp::min, sync::Arc}; static EXECUTION_CONCURRENCY_LEVEL: OnceCell = OnceCell::new(); @@ -1067,7 +1062,7 @@ impl StarcoinVM { // TODO load config by config change event self.load_configs(&data_cache) - .map_err(|_err| VMStatus::Error(StatusCode::STORAGE_ERROR))?; + .map_err(|_err| VMStatus::Error(STORAGE_ERROR))?; let mut gas_left = block_gas_limit.unwrap_or(u64::MAX); @@ -1106,8 +1101,9 @@ impl StarcoinVM { data_cache.push_write_set(output.write_set()) } // TODO load config by config change event + self.check_reconfigure(&data_cache, &output) - .map_err(|_err| VMStatus::Error(StatusCode::STORAGE_ERROR))?; + .map_err(|_err| VMStatus::Error(STORAGE_ERROR))?; #[cfg(feature = "metrics")] if let Some(timer) = timer { @@ -1518,7 +1514,7 @@ impl VMExecutor for StarcoinVM { ) -> Result, VMStatus> { let concurrency_level = Self::get_concurrency_level(); if concurrency_level > 1 { - let (result, err) = crate::parallel_executor::ParallelStarcoinVM::execute_block( + let (result, err) = crate::block_executor::BlockStarcoinVM::execute_block( transactions, state_view, concurrency_level, From a468817b5b52ac4d822f1982facb3714a0bbf901 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Sat, 19 Aug 2023 20:08:55 +0800 Subject: [PATCH 05/89] StateView remove push_write_set function --- vm/types/src/transaction/mod.rs | 4 ++++ vm/vm-runtime/src/data_cache.rs | 24 +++++++++++++------- vm/vm-runtime/src/starcoin_vm.rs | 39 ++++++++++++++++++++++++++------ 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/vm/types/src/transaction/mod.rs b/vm/types/src/transaction/mod.rs index 5a083a80ec..df5dcb5e15 100644 --- a/vm/types/src/transaction/mod.rs +++ b/vm/types/src/transaction/mod.rs @@ -731,6 +731,10 @@ impl TransactionOutput { } table_items } + + pub fn get_writes(&self) -> WriteSet { + self.write_set.clone() + } } /// `TransactionInfo` is the object we store in the transaction accumulator. It consists of the diff --git a/vm/vm-runtime/src/data_cache.rs b/vm/vm-runtime/src/data_cache.rs index ddaf1701bf..e70b6851b7 100644 --- a/vm/vm-runtime/src/data_cache.rs +++ b/vm/vm-runtime/src/data_cache.rs @@ -15,20 +15,17 @@ use starcoin_vm_types::{ state_store::state_key::StateKey, state_view::StateView, vm_status::StatusCode, - write_set::{WriteOp, WriteSet}, }; use std::{ + borrow::Cow, collections::btree_map::BTreeMap, ops::{Deref, DerefMut}, }; -/// A local cache for a given a `StateView`. The cache is private to the Diem layer +/// A local cache for a given a `StateView`. The cache is private to the Starcoin layer /// but can be used as a one shot cache for systems that need a simple `RemoteCache` /// implementation (e.g. tests or benchmarks). /// -/// The cache is responsible to track all changes to the `StateView` that are the result -/// of transaction execution. Those side effects are published at the end of a transaction -/// execution via `StateViewCache::push_write_set`. /// /// `StateViewCache` is responsible to give an up to date view over the data store, /// so that changes executed but not yet committed are visible to subsequent transactions. @@ -37,22 +34,33 @@ use std::{ /// track of incremental changes is vital to the consistency of the data store and the system. pub struct StateViewCache<'a, S> { data_view: &'a S, - data_map: BTreeMap>>, + data_map: Cow<'a, BTreeMap>>>, } impl<'a, S: StateView> StateViewCache<'a, S> { + pub fn from_map_ref( + data_view: &'a S, + data_map_ref: &'a BTreeMap>>, + ) -> Self { + Self { + data_view, + data_map: Cow::Borrowed(data_map_ref), + } + } + /// Create a `StateViewCache` give a `StateView`. Hold updates to the data store and /// forward data request to the `StateView` if not in the local cache. pub fn new(data_view: &'a S) -> Self { StateViewCache { data_view, - data_map: BTreeMap::new(), + data_map: Cow::Owned(BTreeMap::new()), } } // Publishes a `WriteSet` computed at the end of a transaction. // The effect is to build a layer in front of the `StateView` which keeps // track of the data as if the changes were applied immediately. + /* pub(crate) fn push_write_set(&mut self, write_set: &WriteSet) { for (ref ap, ref write_op) in write_set.iter() { match write_op { @@ -65,7 +73,7 @@ impl<'a, S: StateView> StateViewCache<'a, S> { } } } - } + } */ } impl<'block, S: StateView> StateView for StateViewCache<'block, S> { diff --git a/vm/vm-runtime/src/starcoin_vm.rs b/vm/vm-runtime/src/starcoin_vm.rs index 59e798ab8e..730ea50205 100644 --- a/vm/vm-runtime/src/starcoin_vm.rs +++ b/vm/vm-runtime/src/starcoin_vm.rs @@ -38,6 +38,7 @@ use starcoin_types::{ TransactionPayload, TransactionStatus, }, }; +use starcoin_vm_types::write_set::WriteOp; use starcoin_vm_types::{ access::{ModuleAccess, ScriptAccess}, account_address::AccountAddress, @@ -63,6 +64,7 @@ use starcoin_vm_types::{ value::{serialize_values, MoveValue}, vm_status::{KeptVMStatus, StatusCode, VMStatus}, }; +use std::collections::BTreeMap; use std::{cmp::min, sync::Arc}; static EXECUTION_CONCURRENCY_LEVEL: OnceCell = OnceCell::new(); @@ -1057,11 +1059,12 @@ impl StarcoinVM { transactions: Vec, block_gas_limit: Option, ) -> Result, VMStatus> { - let mut data_cache = StateViewCache::new(storage); + let mut data_map = BTreeMap::new(); + let mut result = vec![]; // TODO load config by config change event - self.load_configs(&data_cache) + self.load_configs(storage) .map_err(|_err| VMStatus::Error(STORAGE_ERROR))?; let mut gas_left = block_gas_limit.unwrap_or(u64::MAX); @@ -1073,6 +1076,7 @@ impl StarcoinVM { match block { TransactionBlock::UserTransaction(txns) => { for transaction in txns { + let data_cache = StateViewCache::from_map_ref(storage, &data_map); #[cfg(feature = "metrics")] let timer = self.metrics.as_ref().map(|metrics| { metrics @@ -1097,11 +1101,21 @@ impl StarcoinVM { "Keep transaction gas used must not be zero" ); } - // Push write set to write set - data_cache.push_write_set(output.write_set()) + // Apply the writes + for (ap, write_op) in output.get_writes().into_iter() { + match write_op { + WriteOp::Value(blob) => { + data_map.insert(ap, Some(blob)); + } + WriteOp::Deletion => { + data_map.remove(&ap); + data_map.insert(ap, None); + } + } + } } + let data_cache = StateViewCache::from_map_ref(storage, &data_map); // TODO load config by config change event - self.check_reconfigure(&data_cache, &output) .map_err(|_err| VMStatus::Error(STORAGE_ERROR))?; @@ -1124,6 +1138,7 @@ impl StarcoinVM { } } TransactionBlock::BlockPrologue(block_metadata) => { + let data_cache = StateViewCache::from_map_ref(storage, &data_map); #[cfg(feature = "metrics")] let timer = self.metrics.as_ref().map(|metrics| { metrics @@ -1148,8 +1163,18 @@ impl StarcoinVM { &KeptVMStatus::Executed, "Block metadata transaction keep status must been Executed." ); - // Push write set to write set - data_cache.push_write_set(output.write_set()) + // Apply the writes + for (ap, write_op) in output.get_writes().into_iter() { + match write_op { + WriteOp::Value(blob) => { + data_map.insert(ap, Some(blob)); + } + WriteOp::Deletion => { + data_map.remove(&ap); + data_map.insert(ap, None); + } + } + } } #[cfg(feature = "metrics")] if let Some(timer) = timer { From d541a73f4f18eda4a81d2c773ea021b2d0804803 Mon Sep 17 00:00:00 2001 From: welbon Date: Fri, 1 Sep 2023 23:26:09 +0800 Subject: [PATCH 06/89] [benchmark] merge calculate code from benchmark project --- Cargo.lock | 4 +- vm/e2e-tests/Cargo.toml | 2 +- vm/transaction-benchmarks/Cargo.toml | 2 +- vm/transaction-benchmarks/src/main.rs | 51 ++++++++++++++ vm/transaction-benchmarks/src/measurement.rs | 2 +- vm/transaction-benchmarks/src/transactions.rs | 70 ++++++++++++++++++- vm/vm-runtime/src/block_executor/mod.rs | 28 ++++++++ 7 files changed, 152 insertions(+), 7 deletions(-) create mode 100644 vm/transaction-benchmarks/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index f91825e35a..f66fcbb230 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9807,7 +9807,7 @@ version = "0.1.0" [[package]] name = "starcoin-language-e2e-tests" -version = "1.13.5" +version = "1.13.7" dependencies = [ "anyhow", "bcs", @@ -10783,7 +10783,7 @@ dependencies = [ [[package]] name = "starcoin-transaction-benchmarks" -version = "1.13.5" +version = "1.13.7" dependencies = [ "criterion", "criterion-cpu-time", diff --git a/vm/e2e-tests/Cargo.toml b/vm/e2e-tests/Cargo.toml index 4ff76c0272..d8f9a25fd1 100644 --- a/vm/e2e-tests/Cargo.toml +++ b/vm/e2e-tests/Cargo.toml @@ -4,7 +4,7 @@ authors = { workspace = true } edition = { workspace = true } license = { workspace = true } publish = { workspace = true } -version = "1.13.5" +version = "1.13.7" homepage = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } diff --git a/vm/transaction-benchmarks/Cargo.toml b/vm/transaction-benchmarks/Cargo.toml index 3ef153809f..91546f9e2b 100644 --- a/vm/transaction-benchmarks/Cargo.toml +++ b/vm/transaction-benchmarks/Cargo.toml @@ -4,7 +4,7 @@ authors = { workspace = true } edition = { workspace = true } license = { workspace = true } publish = { workspace = true } -version = "1.13.5" +version = "1.13.7" homepage = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } diff --git a/vm/transaction-benchmarks/src/main.rs b/vm/transaction-benchmarks/src/main.rs new file mode 100644 index 0000000000..e06d8ce89a --- /dev/null +++ b/vm/transaction-benchmarks/src/main.rs @@ -0,0 +1,51 @@ +use num_cpus; +use proptest::prelude::*; +use starcoin_language_e2e_tests::account_universe::P2PTransferGen; +use starcoin_transaction_benchmarks::transactions::TransactionBencher; + +fn main() { + let default_num_accounts = 100; + let default_num_transactions = 1_000; + + let bencher = TransactionBencher::new( + any_with::((1_000, 1_000_000)), + default_num_accounts, + default_num_transactions, + ); + + let acts = [2, 10, 100, 1000, 10000]; + let txns = [1000, 10000]; + let num_warmups = 2; + let num_runs = 10; + + let mut measurements = Vec::new(); + + for block_size in txns { + for num_accounts in acts { + let mut times = + bencher.manual_parallel(num_accounts, block_size, num_warmups, num_runs); + times.sort(); + measurements.push(times); + } + } + + println!("CPUS = {}", num_cpus::get()); + + let mut i = 0; + for block_size in txns { + for num_accounts in acts { + println!( + "PARAMS: num_account = {}, block_size = {}", + num_accounts, block_size + ); + println!("TPS: {:?}", measurements[i]); + let mut sum = 0; + for m in &measurements[i] { + sum += m; + } + println!("AVG TPS = {:?}", sum / measurements[i].len()); + i = i + 1; + } + println!(); + } +} diff --git a/vm/transaction-benchmarks/src/measurement.rs b/vm/transaction-benchmarks/src/measurement.rs index c2fe8afbb7..71622e39d5 100644 --- a/vm/transaction-benchmarks/src/measurement.rs +++ b/vm/transaction-benchmarks/src/measurement.rs @@ -1,4 +1,4 @@ -// Copyright (c) Starcoin +// Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 use criterion::Criterion; diff --git a/vm/transaction-benchmarks/src/transactions.rs b/vm/transaction-benchmarks/src/transactions.rs index 1eca72021d..90882dd730 100644 --- a/vm/transaction-benchmarks/src/transactions.rs +++ b/vm/transaction-benchmarks/src/transactions.rs @@ -84,17 +84,49 @@ where pub fn bench_parallel(&self, b: &mut Bencher) { b.iter_batched( || { - TransactionBenchState::with_size( + ParallelBenchState::with_size( &self.strategy, self.num_accounts, self.num_transactions, ) }, - |state| state.execute_parallel(), + |state| state.execute(), // The input here is the entire list of signed transactions, so it's pretty large. BatchSize::LargeInput, ) } + + pub fn manual_parallel( + &self, + num_accounts: usize, + num_txn: usize, + num_warmups: usize, + num_runs: usize, + ) -> Vec { + let mut ret = Vec::new(); + + let total_runs = num_warmups + num_runs; + for i in 0..total_runs { + let state = ParallelBenchState::with_size(&self.strategy, num_accounts, num_txn); + + if i < num_warmups { + println!("WARMUP - ignore results"); + state.execute(); + } else { + println!( + "RUN bencher for: num_threads = {}, \ + block_size = {}, \ + num_account = {}", + num_cpus::get(), + num_txn, + num_accounts, + ); + ret.push(state.execute()); + } + } + + ret + } } struct TransactionBenchState { @@ -233,3 +265,37 @@ fn universe_strategy( let balance_strategy = log_balance_strategy(max_balance); AccountUniverseGen::strategy(num_accounts, balance_strategy) } + +struct ParallelBenchState { + bench_state: TransactionBenchState, +} + +impl ParallelBenchState { + /// Creates a new benchmark state with the given number of accounts and transactions. + fn with_size(strategy: S, num_accounts: usize, num_transactions: usize) -> Self + where + S: Strategy, + S::Value: AUTransactionGen, + { + Self { + bench_state: TransactionBenchState::with_universe( + strategy, + universe_strategy(num_accounts, num_transactions), + num_transactions, + ), + } + } + + fn execute(self) -> usize { + // let txns = self + // .bench_state + // .transactions + // .into_iter() + // .map(Transaction::UserTransaction) + // .collect(); + + let state_view = self.bench_state.executor.get_state_view(); + // measured - microseconds. + ParallelStarcoinVM::execute_block_tps(self.bench_state.transactions.clone(), state_view) + } +} diff --git a/vm/vm-runtime/src/block_executor/mod.rs b/vm/vm-runtime/src/block_executor/mod.rs index bb9c29d45a..9fb490a6d8 100644 --- a/vm/vm-runtime/src/block_executor/mod.rs +++ b/vm/vm-runtime/src/block_executor/mod.rs @@ -24,6 +24,7 @@ use starcoin_vm_types::{ write_set::{WriteOp, WriteSet}, }; use std::collections::BTreeMap; +use std::time::Instant; impl PTransaction for PreprocessedTransaction { type Key = StateKey; @@ -109,4 +110,31 @@ impl BlockStarcoinVM { Err(Error::UserError(err)) => Err(err), } } + + pub fn execute_block_tps( + transactions: Vec, + state_view: &S, + ) -> usize { + // Verify the signatures of all the transactions in parallel. + // This is time consuming so don't wait and do the checking + // sequentially while executing the transactions. + + // let mut timer = Instant::now(); + let signature_verified_block: Vec = transactions + .par_iter() + .map(|txn| preprocess_transaction(txn.clone())) + .collect(); + // println!("CLONE & Prologue {:?}", timer.elapsed()); + + let executor = + ParallelTransactionExecutor::>::new(num_cpus::get()); + + let timer = Instant::now(); + let useless = executor.execute_transactions_parallel(state_view, signature_verified_block); + let exec_t = timer.elapsed(); + + drop(useless); + + (transactions.len() * 1000 / exec_t.as_millis() as usize) as usize + } } From f6bcca6c1db3c152f1ae1cfb3731176a961b617c Mon Sep 17 00:00:00 2001 From: welbon Date: Tue, 5 Sep 2023 17:52:26 +0800 Subject: [PATCH 07/89] [benchmark] add the parameter for num_threads --- vm/transaction-benchmarks/src/transactions.rs | 23 ++++++++++++++++--- vm/vm-runtime/src/block_executor/mod.rs | 7 ++++-- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/vm/transaction-benchmarks/src/transactions.rs b/vm/transaction-benchmarks/src/transactions.rs index 90882dd730..10071863cd 100644 --- a/vm/transaction-benchmarks/src/transactions.rs +++ b/vm/transaction-benchmarks/src/transactions.rs @@ -88,6 +88,7 @@ where &self.strategy, self.num_accounts, self.num_transactions, + num_cpus::get(), ) }, |state| state.execute(), @@ -107,7 +108,12 @@ where let total_runs = num_warmups + num_runs; for i in 0..total_runs { - let state = ParallelBenchState::with_size(&self.strategy, num_accounts, num_txn); + let state = ParallelBenchState::with_size( + &self.strategy, + num_accounts, + num_txn, + num_cpus::get(), + ); if i < num_warmups { println!("WARMUP - ignore results"); @@ -268,11 +274,17 @@ fn universe_strategy( struct ParallelBenchState { bench_state: TransactionBenchState, + num_threads: usize, } impl ParallelBenchState { /// Creates a new benchmark state with the given number of accounts and transactions. - fn with_size(strategy: S, num_accounts: usize, num_transactions: usize) -> Self + fn with_size( + strategy: S, + num_accounts: usize, + num_transactions: usize, + num_threads: usize, + ) -> Self where S: Strategy, S::Value: AUTransactionGen, @@ -283,6 +295,7 @@ impl ParallelBenchState { universe_strategy(num_accounts, num_transactions), num_transactions, ), + num_threads, } } @@ -296,6 +309,10 @@ impl ParallelBenchState { let state_view = self.bench_state.executor.get_state_view(); // measured - microseconds. - ParallelStarcoinVM::execute_block_tps(self.bench_state.transactions.clone(), state_view) + ParallelStarcoinVM::execute_block_tps( + self.bench_state.transactions.clone(), + state_view, + self.num_threads, + ) } } diff --git a/vm/vm-runtime/src/block_executor/mod.rs b/vm/vm-runtime/src/block_executor/mod.rs index 9fb490a6d8..8d2768892b 100644 --- a/vm/vm-runtime/src/block_executor/mod.rs +++ b/vm/vm-runtime/src/block_executor/mod.rs @@ -114,6 +114,7 @@ impl BlockStarcoinVM { pub fn execute_block_tps( transactions: Vec, state_view: &S, + parallel_level: usize, ) -> usize { // Verify the signatures of all the transactions in parallel. // This is time consuming so don't wait and do the checking @@ -127,7 +128,9 @@ impl BlockStarcoinVM { // println!("CLONE & Prologue {:?}", timer.elapsed()); let executor = - ParallelTransactionExecutor::>::new(num_cpus::get()); + ParallelTransactionExecutor::>::new( + parallel_level, + ); let timer = Instant::now(); let useless = executor.execute_transactions_parallel(state_view, signature_verified_block); @@ -135,6 +138,6 @@ impl BlockStarcoinVM { drop(useless); - (transactions.len() * 1000 / exec_t.as_millis() as usize) as usize + transactions.len() * 1000 / exec_t.as_millis() as usize } } From aa872ad34f9e74cd5331a08f52c5fe55d73cda45 Mon Sep 17 00:00:00 2001 From: welbon Date: Wed, 6 Sep 2023 10:00:25 +0800 Subject: [PATCH 08/89] [benchmark] Add manual_sequence for sequence execution --- vm/transaction-benchmarks/src/transactions.rs | 78 +++++++++++++++---- 1 file changed, 62 insertions(+), 16 deletions(-) diff --git a/vm/transaction-benchmarks/src/transactions.rs b/vm/transaction-benchmarks/src/transactions.rs index 10071863cd..1a7092c4d2 100644 --- a/vm/transaction-benchmarks/src/transactions.rs +++ b/vm/transaction-benchmarks/src/transactions.rs @@ -8,6 +8,7 @@ use proptest::{ test_runner::TestRunner, }; use starcoin_crypto::HashValue; +use std::time::Instant; use starcoin_language_e2e_tests::account::AccountData; use starcoin_language_e2e_tests::{ @@ -97,6 +98,41 @@ where ) } + pub fn manual_sequence( + &self, + num_accounts: usize, + num_txn: usize, + num_warmups: usize, + num_runs: usize, + ) -> Vec { + let mut ret = Vec::new(); + + let total_runs = num_warmups + num_runs; + for i in 0..total_runs { + let state = TransactionBenchState::with_size( + &self.strategy, + num_accounts, + num_txn, + ); + + if i < num_warmups { + println!("WARMUP - ignore results"); + state.execute(); + } else { + println!( + "RUN bencher for: num_threads = {}, \ + block_size = {}, \ + num_account = {}", + num_cpus::get(), + num_txn, + num_accounts, + ); + ret.push(state.execute()); + } + } + ret + } + pub fn manual_parallel( &self, num_accounts: usize, @@ -130,7 +166,6 @@ where ret.push(state.execute()); } } - ret } } @@ -234,31 +269,42 @@ impl TransactionBenchState { } /// Executes this state in a single block. - fn execute(self) { + fn execute(self) -> usize { // The output is ignored here since we're just testing transaction performance, not trying // to assert correctness. - StarcoinVM::execute_block( - self.transactions, - self.executor.get_state_view(), - None, - None, - ) - .expect("VM should not fail to start"); - } + StarcoinVM::set_concurrency_level_once(1); - /// Executes this state in a single block via parallel execution. - fn execute_parallel(self) { - // The output is ignored here since we're just testing transaction performance, not trying - // to assert correctness. - ParallelStarcoinVM::execute_block( + let transactions_len = self.transactions.len(); + + // this bench execution with TPS + let timer = Instant::now(); + let useless = StarcoinVM::execute_block( self.transactions, self.executor.get_state_view(), - num_cpus::get(), None, None, ) .expect("VM should not fail to start"); + + drop(useless); + + let exec_t = timer.elapsed(); + transactions_len * 1000 / exec_t.as_millis() as usize } + + // /// Executes this state in a single block via parallel execution. + // fn execute_parallel(self) { + // // The output is ignored here since we're just testing transaction performance, not trying + // // to assert correctness. + // ParallelStarcoinVM::execute_block( + // self.transactions, + // self.executor.get_state_view(), + // num_cpus::get(), + // None, + // None, + // ) + // .expect("VM should not fail to start"); + // } } /// Returns a strategy for the account universe customized for benchmarks. From 0490351d7596ed397f775e8391e87e40eb8aab19 Mon Sep 17 00:00:00 2001 From: welbon Date: Thu, 7 Sep 2023 19:10:44 +0800 Subject: [PATCH 09/89] [benchmark] Add flamegraph config for transaction_benches --- Cargo.lock | 101 +++++++++++------- vm/transaction-benchmarks/Cargo.toml | 12 ++- .../benches/transaction_benches.rs | 15 ++- 3 files changed, 82 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f66fcbb230..6fae0ea2c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,7 +16,7 @@ checksum = "f728064aca1c318585bf4bb04ffcfac9e75e508ab4e8b1bd9ba5dfe04e2cbed5" dependencies = [ "actix-rt", "actix_derive", - "bitflags", + "bitflags 1.3.2", "bytes 1.4.0", "crossbeam-channel", "futures-core", @@ -738,7 +738,7 @@ version = "0.59.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cexpr", "clang-sys", "clap 2.34.0", @@ -761,7 +761,7 @@ version = "0.65.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cexpr", "clang-sys", "lazy_static 1.4.0", @@ -797,6 +797,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "bitmaps" version = "2.1.0" @@ -1196,7 +1202,7 @@ checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "ansi_term 0.12.1", "atty", - "bitflags", + "bitflags 1.3.2", "strsim 0.8.0", "textwrap 0.11.0", "unicode-width", @@ -1210,7 +1216,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ "atty", - "bitflags", + "bitflags 1.3.2", "clap_derive", "clap_lex", "indexmap", @@ -1269,7 +1275,7 @@ version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1617,7 +1623,7 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "486d44227f71a1ef39554c0dc47e44b9f4139927c75043312690c3f476d1d788" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crossterm_winapi 0.8.0", "libc", "mio 0.7.14", @@ -1633,7 +1639,7 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c85525306c4291d1b73ce93c8acf9c339f9b213aef6c1d85c3830cbf1c16325c" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crossterm_winapi 0.9.0", "libc", "mio 0.7.14", @@ -2722,7 +2728,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ef1a30ae415c3a691a4f41afddc2dbcd6d70baf338368d85ebc1e8ed92cedb9" dependencies = [ "cfg-if 1.0.0", - "rustix", + "rustix 0.36.14", "windows-sys 0.45.0", ] @@ -2874,7 +2880,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" dependencies = [ - "bitflags", + "bitflags 1.3.2", "fuchsia-zircon-sys", ] @@ -3212,7 +3218,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" dependencies = [ - "bitflags", + "bitflags 1.3.2", "ignore", "walkdir", ] @@ -3850,14 +3856,13 @@ checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" [[package]] name = "is-terminal" -version = "0.4.3" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", - "windows-sys 0.45.0", + "rustix 0.38.11", + "windows-sys 0.48.0", ] [[package]] @@ -4141,7 +4146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" dependencies = [ "arrayvec 0.5.2", - "bitflags", + "bitflags 1.3.2", "cfg-if 1.0.0", "ryu", "static_assertions", @@ -4149,9 +4154,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.139" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libloading" @@ -4682,6 +4687,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +[[package]] +name = "linux-raw-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" + [[package]] name = "lock_api" version = "0.3.4" @@ -5939,7 +5950,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab" dependencies = [ "anyhow", - "bitflags", + "bitflags 1.3.2", "byteorder", "libc", "netlink-packet-core", @@ -6018,7 +6029,7 @@ dependencies = [ "async-trait", "asynchronous-codec 0.5.0", "bcs-ext", - "bitflags", + "bitflags 1.3.2", "bs58 0.3.1", "bytes 1.4.0", "derive_more", @@ -6088,7 +6099,7 @@ name = "network-p2p-types" version = "1.13.7" dependencies = [ "anyhow", - "bitflags", + "bitflags 1.3.2", "bytes 1.4.0", "derive_more", "libp2p", @@ -6128,7 +6139,7 @@ version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cc", "cfg-if 1.0.0", "libc", @@ -6141,7 +6152,7 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if 1.0.0", "libc", "memoffset 0.6.5", @@ -6153,7 +6164,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if 1.0.0", "libc", "static_assertions", @@ -6450,7 +6461,7 @@ version = "0.10.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if 1.0.0", "foreign-types", "libc", @@ -7307,7 +7318,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29f1b898011ce9595050a68e60f90bad083ff2987a695a42357134c8381fba70" dependencies = [ "bit-set", - "bitflags", + "bitflags 1.3.2", "byteorder", "lazy_static 1.4.0", "num-traits 0.2.15", @@ -7750,7 +7761,7 @@ version = "10.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c307f7aacdbab3f0adee67d52739a1d71112cc068d6fab169ddeb18e48877fad" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -7848,7 +7859,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -8241,14 +8252,27 @@ version = "0.36.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14e4d67015953998ad0eb82887a0eb0129e18a7e2f3b7b0f6c422fddcd503d62" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.1.4", "windows-sys 0.45.0", ] +[[package]] +name = "rustix" +version = "0.38.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0c3dde1fc030af041adc40e79c0e7fbcf431dd24870053d187d7c66e4b87453" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys 0.4.5", + "windows-sys 0.48.0", +] + [[package]] name = "rustls" version = "0.19.1" @@ -8298,7 +8322,7 @@ version = "9.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db7826789c0e25614b03e5a54a0717a86f9ff6e6e5247f92b369472869320039" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if 1.0.0", "clipboard-win", "dirs-next", @@ -8486,7 +8510,7 @@ version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -10075,7 +10099,7 @@ dependencies = [ "async-std", "async-trait", "bcs-ext", - "bitflags", + "bitflags 1.3.2", "bytes 1.4.0", "derive_more", "fnv", @@ -10789,6 +10813,7 @@ dependencies = [ "criterion-cpu-time", "log 0.4.17", "num_cpus", + "pprof", "proptest", "proptest-derive", "starcoin-crypto", @@ -11366,7 +11391,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75182f12f490e953596550b65ee31bda7c8e043d9386174b353bda50838c3fd" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "system-configuration-sys", ] @@ -12120,7 +12145,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23ed0a32c88b039b73f1b6c5acbd0554bfa5b6be94467375fd947c4de3a02271" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cassowary", "crossterm 0.22.1", "unicode-segmentation", @@ -12875,7 +12900,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f1db1727772c05cf7a2cfece52c3aca8045ca1e176cd517d323489aa3c6d87" dependencies = [ "async-trait", - "bitflags", + "bitflags 1.3.2", "bytes 1.4.0", "cc", "ipnet", @@ -12917,7 +12942,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e3810f0d00c4dccb54c30a4eee815e703232819dec7b007db115791c42aa374" dependencies = [ "base64 0.10.1", - "bitflags", + "bitflags 1.3.2", "byteorder", "bytes 0.4.12", "futures 0.1.31", diff --git a/vm/transaction-benchmarks/Cargo.toml b/vm/transaction-benchmarks/Cargo.toml index 91546f9e2b..9563744909 100644 --- a/vm/transaction-benchmarks/Cargo.toml +++ b/vm/transaction-benchmarks/Cargo.toml @@ -15,18 +15,20 @@ starcoin-crypto = { package = "starcoin-crypto", workspace = true } starcoin-types = { workspace = true } starcoin-vm-runtime = { workspace = true } starcoin-vm-types = { workspace = true } -criterion = { workspace = true, optional = true } +criterion = { workspace = true, optional = true, features = ["html_reports"] } proptest = { workspace = true, optional = true } proptest-derive = { workspace = true, optional = true } +pprof = { version = "0.10", optional = true, features = ["flamegraph", "criterion"] } log = { workspace = true } criterion-cpu-time = "0.1.0" starcoin-language-e2e-tests = { path = "../e2e-tests" } # move-deps = { path = "../../aptos-move/move-deps" } [dev-dependencies] -criterion = { workspace = true } +criterion = { workspace = true, features = ["html_reports"] } proptest = { workspace = true } proptest-derive = { workspace = true } +pprof = { version = "0.10", features = ["flamegraph", "criterion"] } [[bench]] name = "transaction_benches" @@ -37,5 +39,9 @@ required-features = ["fuzzing"] fuzzing = [ "criterion", "proptest", - "proptest-derive" + "proptest-derive", + "pprof" ] +flamegraph = [] +html_reports = [] + diff --git a/vm/transaction-benchmarks/benches/transaction_benches.rs b/vm/transaction-benchmarks/benches/transaction_benches.rs index 9d4552ed5b..481bdd42f7 100644 --- a/vm/transaction-benchmarks/benches/transaction_benches.rs +++ b/vm/transaction-benchmarks/benches/transaction_benches.rs @@ -1,18 +1,21 @@ // Copyright (c) Starcoin // SPDX-License-Identifier: Apache-2.0 +use std::fs::File; use criterion::{criterion_group, criterion_main, measurement::Measurement, Criterion}; use proptest::prelude::*; use starcoin_language_e2e_tests::account_universe::P2PTransferGen; use starcoin_transaction_benchmarks::{ - measurement::wall_time_measurement, transactions::TransactionBencher, + transactions::TransactionBencher, }; +use pprof::criterion::{Output, PProfProfiler}; // // Transaction benchmarks // + fn peer_to_peer(c: &mut Criterion) { - let default_num_accounts = 10_000; + let default_num_accounts = 1_000; let default_num_transactions = 10_000; c.bench_function("peer_to_peer", |b| { let bencher = TransactionBencher::new( @@ -20,22 +23,24 @@ fn peer_to_peer(c: &mut Criterion) { default_num_accounts, default_num_transactions, ); - bencher.bench(b) + bencher.bench(b); }); c.bench_function("peer_to_peer_parallel", |b| { + let bencher = TransactionBencher::new( any_with::((10_000, 10_000_000)), default_num_accounts, default_num_transactions, ); - bencher.bench_parallel(b) + bencher.bench_parallel(b); }); } criterion_group!( name = txn_benches; - config = wall_time_measurement().sample_size(10); + // config = wall_time_measurement().sample_size(10); + config = Criterion::default().with_profiler(PProfProfiler::new(10, Output::Flamegraph(None))); targets = peer_to_peer ); From 46e9cb815c920af1dcf23ec3c595c071ab984092 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Fri, 8 Sep 2023 10:29:07 +0800 Subject: [PATCH 10/89] build_test.yml use branch tps_benchmark --- .github/workflows/build_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 5a7ffd728f..9fb08cdd7d 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -3,7 +3,7 @@ on: workflow_dispatch: pull_request: branches: - - master + - tps_benchmark jobs: build-and-test: From 5cae38f177303f95bee988ad0f6fec836b2f28d0 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Fri, 8 Sep 2023 11:31:28 +0800 Subject: [PATCH 11/89] add stm flamegraph.sh --- .github/workflows/build_test.yml | 38 +++++--------------------------- scripts/stm_flamegraph.sh | 13 +++++++++++ 2 files changed, 18 insertions(+), 33 deletions(-) create mode 100755 scripts/stm_flamegraph.sh diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 9fb08cdd7d..1b69245860 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -15,44 +15,16 @@ jobs: uses: actions/checkout@v1 with: submodules: recursive - - name: run fmt check - uses: actions-rs/cargo@v1 - with: - command: fmt - args: -- --check - name: setup environment run: bash ./scripts/dev_setup.sh -b -t -y -m - name: run cargo clean uses: actions-rs/cargo@v1 with: command: clean - - name: run cargo check - uses: actions-rs/cargo@v1 + - name: run flamegraph + run: bash ./scripts/stm_flamegraph.sh env: - RUSTFLAGS: -D warnings - with: - command: clippy - args: --all-targets - - name: build - uses: actions-rs/cargo@v1 - with: - command: build - args: --all - - name: test - run: ./scripts/nextest.sh -# - name: check changed files -# run: bash ./scripts/changed_files.sh - - name: Doc Tests - uses: actions-rs/cargo@v1 - with: - command: test - args: --doc - - name: integration test dev environment - env: - RUST_LOG: info + RUST_LOG: error RUST_BACKTRACE: full - STARCOIN_WS: ${{ secrets.STARCOIN_WS }} - uses: actions-rs/cargo@v1 - with: - command: test - args: --test integration -- -e cmd + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} diff --git a/scripts/stm_flamegraph.sh b/scripts/stm_flamegraph.sh new file mode 100755 index 0000000000..17682dfdc8 --- /dev/null +++ b/scripts/stm_flamegraph.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +STARCOIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd .. && pwd)" + +if [[ "$(uname)" != "Linux" ]]; then + echo "run flamegraph only in linux. exit" +fi + + +cmd="cargo bench -p starcoin-transaction-benchmarks --features fuzzing" +echo "run flamegraph with cmd: ${cmd}" +eval "$cmd" + From 3d91cc7fbb4b52643bf89a491fac15589903e3c1 Mon Sep 17 00:00:00 2001 From: welbon Date: Fri, 8 Sep 2023 11:57:20 +0800 Subject: [PATCH 12/89] [benchmark] Add flamegraph config for script --- scripts/stm_flamegraph.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/stm_flamegraph.sh b/scripts/stm_flamegraph.sh index 17682dfdc8..73a344c2fc 100755 --- a/scripts/stm_flamegraph.sh +++ b/scripts/stm_flamegraph.sh @@ -7,7 +7,7 @@ if [[ "$(uname)" != "Linux" ]]; then fi -cmd="cargo bench -p starcoin-transaction-benchmarks --features fuzzing" +cmd="cargo bench -p starcoin-transaction-benchmarks --features fuzzing,flamegraph" echo "run flamegraph with cmd: ${cmd}" eval "$cmd" From 625abaeba76272c6c6e39aa8f545ed0760a3bac2 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Fri, 8 Sep 2023 14:08:25 +0800 Subject: [PATCH 13/89] optimize mod StarcoinVM log --- .../benches/transaction_benches.rs | 9 ++---- vm/transaction-benchmarks/src/transactions.rs | 6 +--- vm/vm-runtime/src/starcoin_vm.rs | 29 ++++++++++++------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/vm/transaction-benchmarks/benches/transaction_benches.rs b/vm/transaction-benchmarks/benches/transaction_benches.rs index 481bdd42f7..24a4d702a4 100644 --- a/vm/transaction-benchmarks/benches/transaction_benches.rs +++ b/vm/transaction-benchmarks/benches/transaction_benches.rs @@ -1,14 +1,12 @@ // Copyright (c) Starcoin // SPDX-License-Identifier: Apache-2.0 -use std::fs::File; use criterion::{criterion_group, criterion_main, measurement::Measurement, Criterion}; +use pprof::criterion::{Output, PProfProfiler}; use proptest::prelude::*; use starcoin_language_e2e_tests::account_universe::P2PTransferGen; -use starcoin_transaction_benchmarks::{ - transactions::TransactionBencher, -}; -use pprof::criterion::{Output, PProfProfiler}; +use starcoin_transaction_benchmarks::transactions::TransactionBencher; +use std::fs::File; // // Transaction benchmarks @@ -27,7 +25,6 @@ fn peer_to_peer(c: &mut Criterion) { }); c.bench_function("peer_to_peer_parallel", |b| { - let bencher = TransactionBencher::new( any_with::((10_000, 10_000_000)), default_num_accounts, diff --git a/vm/transaction-benchmarks/src/transactions.rs b/vm/transaction-benchmarks/src/transactions.rs index 1a7092c4d2..872cae3f4b 100644 --- a/vm/transaction-benchmarks/src/transactions.rs +++ b/vm/transaction-benchmarks/src/transactions.rs @@ -109,11 +109,7 @@ where let total_runs = num_warmups + num_runs; for i in 0..total_runs { - let state = TransactionBenchState::with_size( - &self.strategy, - num_accounts, - num_txn, - ); + let state = TransactionBenchState::with_size(&self.strategy, num_accounts, num_txn); if i < num_warmups { println!("WARMUP - ignore results"); diff --git a/vm/vm-runtime/src/starcoin_vm.rs b/vm/vm-runtime/src/starcoin_vm.rs index 730ea50205..f167fb1c87 100644 --- a/vm/vm-runtime/src/starcoin_vm.rs +++ b/vm/vm-runtime/src/starcoin_vm.rs @@ -910,6 +910,7 @@ impl StarcoinVM { &self, storage: &S, txn: SignedUserTransaction, + use_stm: bool, ) -> (VMStatus, TransactionOutput) { let txn_data = match TransactionMetadata::new(&txn) { Ok(txn_data) => txn_data, @@ -957,17 +958,21 @@ impl StarcoinVM { }; match result { Ok(status_and_output) => { - log_vm_status( - txn.id(), - &txn_data, - &status_and_output.0, - Some(&status_and_output.1), - ); + if !use_stm { + log_vm_status( + txn.id(), + &txn_data, + &status_and_output.0, + Some(&status_and_output.1), + ); + } status_and_output } Err(err) => { let txn_status = TransactionStatus::from(err.clone()); - log_vm_status(txn.id(), &txn_data, &err, None); + if !use_stm { + log_vm_status(txn.id(), &txn_data, &err, None); + } if txn_status.is_discarded() { discard_error_vm_status(err) } else { @@ -1085,8 +1090,11 @@ impl StarcoinVM { .start_timer() }); let gas_unit_price = transaction.gas_unit_price(); - let (status, output) = self - .execute_user_transaction(&data_cache.as_move_resolver(), transaction); + let (status, output) = self.execute_user_transaction( + &data_cache.as_move_resolver(), + transaction, + false, + ); // only need to check for user transactions. match gas_left.checked_sub(output.gas_used()) { Some(l) => gas_left = l, @@ -1600,7 +1608,8 @@ impl VMAdapter for StarcoinVM { Ok(match txn { PreprocessedTransaction::UserTransaction(txn) => { let sender = txn.sender().to_string(); - let (vm_status, output) = self.execute_user_transaction(data_cache, *txn.clone()); + let (vm_status, output) = + self.execute_user_transaction(data_cache, *txn.clone(), true); // XXX FIXME YSG // let gas_unit_price = transaction.gas_unit_price(); think about gas_used OutOfGas (vm_status, output, Some(sender)) From 2da9d9eb91b6bb512ee374b4e563a072c3154ce5 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Fri, 8 Sep 2023 15:15:50 +0800 Subject: [PATCH 14/89] update build_test.yml branch name --- .github/workflows/build_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 1b69245860..d49629ff93 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -3,7 +3,7 @@ on: workflow_dispatch: pull_request: branches: - - tps_benchmark + - block_executor_optimize_tps jobs: build-and-test: From 295d6590704ce8e3994e7d3f434d5ffdadbb6279 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Fri, 8 Sep 2023 15:56:13 +0800 Subject: [PATCH 15/89] update name --- vm/e2e-tests/src/executor.rs | 2 +- vm/transaction-benchmarks/src/transactions.rs | 6 ++---- vm/vm-runtime/src/block_executor/mod.rs | 4 +--- vm/vm-runtime/src/move_vm_ext/session.rs | 7 +++++-- vm/vm-runtime/src/starcoin_vm.rs | 4 ++-- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/vm/e2e-tests/src/executor.rs b/vm/e2e-tests/src/executor.rs index c738257cc4..ded53c6f4f 100644 --- a/vm/e2e-tests/src/executor.rs +++ b/vm/e2e-tests/src/executor.rs @@ -364,7 +364,7 @@ impl FakeExecutor { &self, txn_block: Vec, ) -> Result, VMStatus> { - let (result, _) = ParallelStarcoinVM::execute_block( + let (result, _) = BlockStarcoinVM::execute_block( txn_block, &self.data_store, num_cpus::get(), diff --git a/vm/transaction-benchmarks/src/transactions.rs b/vm/transaction-benchmarks/src/transactions.rs index 872cae3f4b..aad65c358c 100644 --- a/vm/transaction-benchmarks/src/transactions.rs +++ b/vm/transaction-benchmarks/src/transactions.rs @@ -19,9 +19,7 @@ use starcoin_language_e2e_tests::{ use starcoin_types::{block_metadata::BlockMetadata, transaction::Transaction}; -use starcoin_vm_runtime::{ - parallel_executor::ParallelStarcoinVM, starcoin_vm::StarcoinVM, VMExecutor, -}; +use starcoin_vm_runtime::{block_executor::BlockStarcoinVM, starcoin_vm::StarcoinVM, VMExecutor}; use starcoin_vm_types::genesis_config::ChainId; use starcoin_vm_types::transaction::authenticator::AuthenticationKey; @@ -351,7 +349,7 @@ impl ParallelBenchState { let state_view = self.bench_state.executor.get_state_view(); // measured - microseconds. - ParallelStarcoinVM::execute_block_tps( + BlockStarcoinVM::execute_block_tps( self.bench_state.transactions.clone(), state_view, self.num_threads, diff --git a/vm/vm-runtime/src/block_executor/mod.rs b/vm/vm-runtime/src/block_executor/mod.rs index 8d2768892b..898640fa9b 100644 --- a/vm/vm-runtime/src/block_executor/mod.rs +++ b/vm/vm-runtime/src/block_executor/mod.rs @@ -128,9 +128,7 @@ impl BlockStarcoinVM { // println!("CLONE & Prologue {:?}", timer.elapsed()); let executor = - ParallelTransactionExecutor::>::new( - parallel_level, - ); + BlockExecutor::>::new(parallel_level); let timer = Instant::now(); let useless = executor.execute_transactions_parallel(state_view, signature_verified_block); diff --git a/vm/vm-runtime/src/move_vm_ext/session.rs b/vm/vm-runtime/src/move_vm_ext/session.rs index 6a78ea101e..e165a24646 100644 --- a/vm/vm-runtime/src/move_vm_ext/session.rs +++ b/vm/vm-runtime/src/move_vm_ext/session.rs @@ -17,12 +17,15 @@ use starcoin_vm_types::{ block_metadata::BlockMetadata, contract_event::ContractEvent, event::EventKey, - state_store::state_key::StateKey, + state_store::{ + state_key::StateKey, + table::{TableHandle, TableInfo}, + }, transaction::SignatureCheckedTransaction, transaction_metadata::TransactionMetadata, write_set::{WriteOp, WriteSet, WriteSetMut}, }; -use std::convert::TryFrom; +use std::{collections::BTreeMap, convert::TryFrom}; #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, CryptoHasher, CryptoHash)] pub enum SessionId { diff --git a/vm/vm-runtime/src/starcoin_vm.rs b/vm/vm-runtime/src/starcoin_vm.rs index f167fb1c87..fd4d005771 100644 --- a/vm/vm-runtime/src/starcoin_vm.rs +++ b/vm/vm-runtime/src/starcoin_vm.rs @@ -54,8 +54,8 @@ use starcoin_vm_types::{ language_storage::{ModuleId, TypeTag}, on_chain_config::{ GasSchedule, MoveLanguageVersion, OnChainConfig, VMConfig, Version, - G_GAS_CONSTANTS_IDENTIFIER, G_GAS_SCHEDULE_GAS_SCHEDULE, G_GAS_SCHEDULE_IDENTIFIER, - G_INSTRUCTION_SCHEDULE_IDENTIFIER, G_NATIVE_SCHEDULE_IDENTIFIER, G_VM_CONFIG_IDENTIFIER, + G_GAS_CONSTANTS_IDENTIFIER, G_INSTRUCTION_SCHEDULE_IDENTIFIER, + G_NATIVE_SCHEDULE_IDENTIFIER, G_VM_CONFIG_IDENTIFIER, }, state_store::state_key::StateKey, state_view::{StateReaderExt, StateView}, From d9ee1cf45898053e92c8a8a030ba238af72e56d5 Mon Sep 17 00:00:00 2001 From: welbon Date: Fri, 8 Sep 2023 15:45:28 +0800 Subject: [PATCH 16/89] [benchmark] Add flamegraph file to github CI artifact after action completed --- .github/workflows/build_test.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index d49629ff93..52cc08e655 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -28,3 +28,10 @@ jobs: RUST_BACKTRACE: full AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + - name: upload flamegraph to artifact + uses: actions/upload-artifact@v2 + with: + name: flamegraph-artifact + path: | + ./target/criterion/peer_to_peer_parallel/profile/p2p-p.1.flamegraph.svg + ./target/criterion/peer_to_peer_parallel/profile/p2p-p-flamegraph.svg From 7a48923720e1d9cb508a70cc9bd0b34c34f094c8 Mon Sep 17 00:00:00 2001 From: welbon Date: Fri, 8 Sep 2023 16:04:25 +0800 Subject: [PATCH 17/89] [benchmark] Split the peer_to_peer benchmark into two targets --- .../benches/transaction_benches.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/vm/transaction-benchmarks/benches/transaction_benches.rs b/vm/transaction-benchmarks/benches/transaction_benches.rs index 24a4d702a4..a664d325ce 100644 --- a/vm/transaction-benchmarks/benches/transaction_benches.rs +++ b/vm/transaction-benchmarks/benches/transaction_benches.rs @@ -12,23 +12,26 @@ use std::fs::File; // Transaction benchmarks // +const DEFAULT_NUM_ACCOUNTS: usize = 1_000; +const DEFAULT_NUM_TRANSACTIONS: usize = 10_000; + fn peer_to_peer(c: &mut Criterion) { - let default_num_accounts = 1_000; - let default_num_transactions = 10_000; c.bench_function("peer_to_peer", |b| { let bencher = TransactionBencher::new( any_with::((10_000, 10_000_000)), - default_num_accounts, - default_num_transactions, + DEFAULT_NUM_ACCOUNTS, + DEFAULT_NUM_TRANSACTIONS, ); bencher.bench(b); }); +} +fn peer_to_peer_parallel(c: &mut Criterion) { c.bench_function("peer_to_peer_parallel", |b| { let bencher = TransactionBencher::new( any_with::((10_000, 10_000_000)), - default_num_accounts, - default_num_transactions, + DEFAULT_NUM_ACCOUNTS, + DEFAULT_NUM_TRANSACTIONS, ); bencher.bench_parallel(b); }); @@ -38,7 +41,7 @@ criterion_group!( name = txn_benches; // config = wall_time_measurement().sample_size(10); config = Criterion::default().with_profiler(PProfProfiler::new(10, Output::Flamegraph(None))); - targets = peer_to_peer + targets = peer_to_peer, peer_to_peer_parallel ); criterion_main!(txn_benches); From 0f783c5cdfd2da13b46297cefd8293ece283624d Mon Sep 17 00:00:00 2001 From: welbon Date: Fri, 8 Sep 2023 16:54:08 +0800 Subject: [PATCH 18/89] [benchmark] Split the peer_to_peer benchmark into two targets --- .github/workflows/build_test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 52cc08e655..5e23b3f457 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -33,5 +33,5 @@ jobs: with: name: flamegraph-artifact path: | - ./target/criterion/peer_to_peer_parallel/profile/p2p-p.1.flamegraph.svg - ./target/criterion/peer_to_peer_parallel/profile/p2p-p-flamegraph.svg + ./target/criterion/peer_to_peer/profile/flamegraph.svg + ./target/criterion/peer_to_peer_parallel/profile/flamegraph.svg From 4d186bf273ce90e50bb00cf5f988fb05fe04ab77 Mon Sep 17 00:00:00 2001 From: welbon Date: Fri, 8 Sep 2023 17:22:14 +0800 Subject: [PATCH 19/89] [benchmark] Split the peer_to_peer benchmark into two targets --- .github/workflows/build_test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 5e23b3f457..aea25a0e48 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -33,5 +33,5 @@ jobs: with: name: flamegraph-artifact path: | - ./target/criterion/peer_to_peer/profile/flamegraph.svg - ./target/criterion/peer_to_peer_parallel/profile/flamegraph.svg + ./peer_to_peer/profile/flamegraph.svg + ./peer_to_peer_parallel/profile/flamegraph.svg From 2855480909c18bb991e77fb9a75e3d7ad9301098 Mon Sep 17 00:00:00 2001 From: welbon Date: Fri, 8 Sep 2023 19:37:10 +0800 Subject: [PATCH 20/89] [benchmark] fix flamegraph output command --- scripts/stm_flamegraph.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/stm_flamegraph.sh b/scripts/stm_flamegraph.sh index 73a344c2fc..30cd8dd04d 100755 --- a/scripts/stm_flamegraph.sh +++ b/scripts/stm_flamegraph.sh @@ -7,7 +7,7 @@ if [[ "$(uname)" != "Linux" ]]; then fi -cmd="cargo bench -p starcoin-transaction-benchmarks --features fuzzing,flamegraph" +cmd="cargo bench -p starcoin-transaction-benchmarks --bench transaction_benches --features fuzzing,flamegraph -- --profile-time=20" echo "run flamegraph with cmd: ${cmd}" eval "$cmd" From 474b8ca51045d51648ac2bddeaee95b080396333 Mon Sep 17 00:00:00 2001 From: welbon Date: Fri, 8 Sep 2023 19:38:57 +0800 Subject: [PATCH 21/89] [benchmark] fix flamegraph output command --- .github/workflows/build_test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index aea25a0e48..5e23b3f457 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -33,5 +33,5 @@ jobs: with: name: flamegraph-artifact path: | - ./peer_to_peer/profile/flamegraph.svg - ./peer_to_peer_parallel/profile/flamegraph.svg + ./target/criterion/peer_to_peer/profile/flamegraph.svg + ./target/criterion/peer_to_peer_parallel/profile/flamegraph.svg From 77a18aba6e9b8ec06a9573edb60cf4c529666fdd Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Mon, 11 Sep 2023 09:59:38 +0800 Subject: [PATCH 22/89] set num_threads --- vm/transaction-benchmarks/src/transactions.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/vm/transaction-benchmarks/src/transactions.rs b/vm/transaction-benchmarks/src/transactions.rs index aad65c358c..fe9a2b5c37 100644 --- a/vm/transaction-benchmarks/src/transactions.rs +++ b/vm/transaction-benchmarks/src/transactions.rs @@ -8,7 +8,7 @@ use proptest::{ test_runner::TestRunner, }; use starcoin_crypto::HashValue; -use std::time::Instant; +use std::time::{Instant, SystemTime}; use starcoin_language_e2e_tests::account::AccountData; use starcoin_language_e2e_tests::{ @@ -81,19 +81,23 @@ where /// Runs the bencher. pub fn bench_parallel(&self, b: &mut Bencher) { + let start_time = SystemTime::now(); + let num = 4; b.iter_batched( || { ParallelBenchState::with_size( &self.strategy, self.num_accounts, self.num_transactions, - num_cpus::get(), + num, ) }, |state| state.execute(), // The input here is the entire list of signed transactions, so it's pretty large. BatchSize::LargeInput, - ) + ); + let use_time = SystemTime::now().duration_since(start_time).unwrap(); + println!("cpu num = {}, cost time = {}", num, use_time.as_secs()); } pub fn manual_sequence( From 68b05a99a1a1079c0a1a1d96acfaef55becc8670 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Mon, 11 Sep 2023 10:13:55 +0800 Subject: [PATCH 23/89] set num_thread=8 --- vm/transaction-benchmarks/src/transactions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/transaction-benchmarks/src/transactions.rs b/vm/transaction-benchmarks/src/transactions.rs index fe9a2b5c37..c3a4381e89 100644 --- a/vm/transaction-benchmarks/src/transactions.rs +++ b/vm/transaction-benchmarks/src/transactions.rs @@ -82,7 +82,7 @@ where /// Runs the bencher. pub fn bench_parallel(&self, b: &mut Bencher) { let start_time = SystemTime::now(); - let num = 4; + let num = 8; b.iter_batched( || { ParallelBenchState::with_size( From 980b16cd5201fe5d7a98366ab01b18e1e54e2238 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Mon, 11 Sep 2023 14:54:35 +0800 Subject: [PATCH 24/89] set concurrency_level --- Cargo.lock | 6 +++--- scripts/stm_flamegraph.sh | 4 +++- vm/block-executor/Cargo.toml | 2 +- vm/mvhashmap/Cargo.toml | 2 +- vm/proptest-helpers/Cargo.toml | 2 +- vm/transaction-benchmarks/src/main.rs | 14 +++++++++++--- vm/transaction-benchmarks/src/transactions.rs | 12 +++++------- 7 files changed, 25 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6fae0ea2c7..d2387d49e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9245,7 +9245,7 @@ dependencies = [ [[package]] name = "starcoin-block-executor" -version = "1.13.5" +version = "1.13.7" dependencies = [ "anyhow", "arc-swap", @@ -10052,7 +10052,7 @@ dependencies = [ [[package]] name = "starcoin-mvhashmap" -version = "1.13.5" +version = "1.13.7" dependencies = [ "arc-swap", "crossbeam", @@ -10325,7 +10325,7 @@ dependencies = [ [[package]] name = "starcoin-proptest-helpers" -version = "1.13.5" +version = "1.13.7" dependencies = [ "crossbeam", "proptest", diff --git a/scripts/stm_flamegraph.sh b/scripts/stm_flamegraph.sh index 30cd8dd04d..a3a8479463 100755 --- a/scripts/stm_flamegraph.sh +++ b/scripts/stm_flamegraph.sh @@ -6,8 +6,10 @@ if [[ "$(uname)" != "Linux" ]]; then echo "run flamegraph only in linux. exit" fi +cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing" +echo "run tps with cmd: ${cmd}" +eval "$cmd" cmd="cargo bench -p starcoin-transaction-benchmarks --bench transaction_benches --features fuzzing,flamegraph -- --profile-time=20" echo "run flamegraph with cmd: ${cmd}" eval "$cmd" - diff --git a/vm/block-executor/Cargo.toml b/vm/block-executor/Cargo.toml index 277de7df4f..d8062ef10b 100644 --- a/vm/block-executor/Cargo.toml +++ b/vm/block-executor/Cargo.toml @@ -5,7 +5,7 @@ edition = { workspace = true } license = { workspace = true } name = "starcoin-block-executor" publish = { workspace = true } -version = "1.13.5" +version = "1.13.7" homepage = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } diff --git a/vm/mvhashmap/Cargo.toml b/vm/mvhashmap/Cargo.toml index 1c061e5eab..63dfba1d8f 100644 --- a/vm/mvhashmap/Cargo.toml +++ b/vm/mvhashmap/Cargo.toml @@ -5,7 +5,7 @@ edition = { workspace = true } license = { workspace = true } name = "starcoin-mvhashmap" publish = { workspace = true } -version = "1.13.5" +version = "1.13.7" homepage = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } diff --git a/vm/proptest-helpers/Cargo.toml b/vm/proptest-helpers/Cargo.toml index 70ee92ab82..c06e051838 100644 --- a/vm/proptest-helpers/Cargo.toml +++ b/vm/proptest-helpers/Cargo.toml @@ -4,7 +4,7 @@ authors = { workspace = true } edition = { workspace = true } license = { workspace = true } publish = { workspace = true } -version = "1.13.5" +version = "1.13.7" homepage = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } diff --git a/vm/transaction-benchmarks/src/main.rs b/vm/transaction-benchmarks/src/main.rs index e06d8ce89a..5c0f33a2fb 100644 --- a/vm/transaction-benchmarks/src/main.rs +++ b/vm/transaction-benchmarks/src/main.rs @@ -13,17 +13,25 @@ fn main() { default_num_transactions, ); - let acts = [2, 10, 100, 1000, 10000]; + let acts = [1000]; let txns = [1000, 10000]; let num_warmups = 2; let num_runs = 10; + let num_threads = 2; + + println!("num cpus = {}", num_cpus::get()); let mut measurements = Vec::new(); for block_size in txns { for num_accounts in acts { - let mut times = - bencher.manual_parallel(num_accounts, block_size, num_warmups, num_runs); + let mut times = bencher.manual_parallel( + num_accounts, + block_size, + num_warmups, + num_runs, + num_threads, + ); times.sort(); measurements.push(times); } diff --git a/vm/transaction-benchmarks/src/transactions.rs b/vm/transaction-benchmarks/src/transactions.rs index c3a4381e89..b73d01e961 100644 --- a/vm/transaction-benchmarks/src/transactions.rs +++ b/vm/transaction-benchmarks/src/transactions.rs @@ -106,6 +106,7 @@ where num_txn: usize, num_warmups: usize, num_runs: usize, + concurrency_level: usize, ) -> Vec { let mut ret = Vec::new(); @@ -121,9 +122,7 @@ where "RUN bencher for: num_threads = {}, \ block_size = {}, \ num_account = {}", - num_cpus::get(), - num_txn, - num_accounts, + concurrency_level, num_txn, num_accounts, ); ret.push(state.execute()); } @@ -137,6 +136,7 @@ where num_txn: usize, num_warmups: usize, num_runs: usize, + concurrency_level: usize, ) -> Vec { let mut ret = Vec::new(); @@ -146,7 +146,7 @@ where &self.strategy, num_accounts, num_txn, - num_cpus::get(), + concurrency_level, ); if i < num_warmups { @@ -157,9 +157,7 @@ where "RUN bencher for: num_threads = {}, \ block_size = {}, \ num_account = {}", - num_cpus::get(), - num_txn, - num_accounts, + concurrency_level, num_txn, num_accounts, ); ret.push(state.execute()); } From 888eb50e4715834541f981ec4fe5a2eda393a02e Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Mon, 11 Sep 2023 15:44:30 +0800 Subject: [PATCH 25/89] add different num_threads --- Cargo.lock | 1 + scripts/stm_flamegraph.sh | 46 ++++++++++++++++++++++++++- vm/transaction-benchmarks/Cargo.toml | 1 + vm/transaction-benchmarks/src/main.rs | 12 ++++++- 4 files changed, 58 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d2387d49e7..3fac300827 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10809,6 +10809,7 @@ dependencies = [ name = "starcoin-transaction-benchmarks" version = "1.13.7" dependencies = [ + "clap 3.2.23", "criterion", "criterion-cpu-time", "log 0.4.17", diff --git a/scripts/stm_flamegraph.sh b/scripts/stm_flamegraph.sh index a3a8479463..02a12d41e8 100755 --- a/scripts/stm_flamegraph.sh +++ b/scripts/stm_flamegraph.sh @@ -6,7 +6,51 @@ if [[ "$(uname)" != "Linux" ]]; then echo "run flamegraph only in linux. exit" fi -cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing" +cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 2" +echo "run tps with cmd: ${cmd}" +eval "$cmd" + +cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 4" +echo "run tps with cmd: ${cmd}" +eval "$cmd" + +cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 6" +echo "run tps with cmd: ${cmd}" +eval "$cmd" + +cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 8" +echo "run tps with cmd: ${cmd}" +eval "$cmd" + +cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 10" +echo "run tps with cmd: ${cmd}" +eval "$cmd" + +cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 12" +echo "run tps with cmd: ${cmd}" +eval "$cmd" + +cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 14" +echo "run tps with cmd: ${cmd}" +eval "$cmd" + +cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 16" +echo "run tps with cmd: ${cmd}" +eval "$cmd" + +cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 18" +echo "run tps with cmd: ${cmd}" +eval "$cmd" + +cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 20" +echo "run tps with cmd: ${cmd}" +eval "$cmd" + +cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 22" +echo "run tps with cmd: ${cmd}" +eval "$cmd" + +cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 24" echo "run tps with cmd: ${cmd}" eval "$cmd" diff --git a/vm/transaction-benchmarks/Cargo.toml b/vm/transaction-benchmarks/Cargo.toml index 9563744909..2d4f4efd5b 100644 --- a/vm/transaction-benchmarks/Cargo.toml +++ b/vm/transaction-benchmarks/Cargo.toml @@ -23,6 +23,7 @@ log = { workspace = true } criterion-cpu-time = "0.1.0" starcoin-language-e2e-tests = { path = "../e2e-tests" } # move-deps = { path = "../../aptos-move/move-deps" } +clap = { workspace = true } [dev-dependencies] criterion = { workspace = true, features = ["html_reports"] } diff --git a/vm/transaction-benchmarks/src/main.rs b/vm/transaction-benchmarks/src/main.rs index 5c0f33a2fb..04623c5794 100644 --- a/vm/transaction-benchmarks/src/main.rs +++ b/vm/transaction-benchmarks/src/main.rs @@ -2,8 +2,18 @@ use num_cpus; use proptest::prelude::*; use starcoin_language_e2e_tests::account_universe::P2PTransferGen; use starcoin_transaction_benchmarks::transactions::TransactionBencher; +use clap::Parser; + +#[derive(Debug, Parser)] +#[clap(name = "concurrency level", about = "concurrency level")] +pub struct ConcurrencyLevelOpt { + #[clap(long, short = 'n')] + /// concurrency level + pub concurrency_level: usize, +} fn main() { + let opt: ConcurrencyLevelOpt = ConcurrencyLevelOpt::parse(); let default_num_accounts = 100; let default_num_transactions = 1_000; @@ -17,7 +27,7 @@ fn main() { let txns = [1000, 10000]; let num_warmups = 2; let num_runs = 10; - let num_threads = 2; + let num_threads = opt.concurrency_level; println!("num cpus = {}", num_cpus::get()); From 76e709dd4fc46c0e1e42f0e4ad1e2ebc4003ea4a Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Mon, 11 Sep 2023 16:33:54 +0800 Subject: [PATCH 26/89] enlarge num accounts --- scripts/stm_flamegraph.sh | 20 -------------------- vm/transaction-benchmarks/src/main.rs | 4 ++-- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/scripts/stm_flamegraph.sh b/scripts/stm_flamegraph.sh index 02a12d41e8..98e8946036 100755 --- a/scripts/stm_flamegraph.sh +++ b/scripts/stm_flamegraph.sh @@ -14,42 +14,22 @@ cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 4" echo "run tps with cmd: ${cmd}" eval "$cmd" -cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 6" -echo "run tps with cmd: ${cmd}" -eval "$cmd" - cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 8" echo "run tps with cmd: ${cmd}" eval "$cmd" -cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 10" -echo "run tps with cmd: ${cmd}" -eval "$cmd" - cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 12" echo "run tps with cmd: ${cmd}" eval "$cmd" -cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 14" -echo "run tps with cmd: ${cmd}" -eval "$cmd" - cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 16" echo "run tps with cmd: ${cmd}" eval "$cmd" -cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 18" -echo "run tps with cmd: ${cmd}" -eval "$cmd" - cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 20" echo "run tps with cmd: ${cmd}" eval "$cmd" -cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 22" -echo "run tps with cmd: ${cmd}" -eval "$cmd" - cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 24" echo "run tps with cmd: ${cmd}" eval "$cmd" diff --git a/vm/transaction-benchmarks/src/main.rs b/vm/transaction-benchmarks/src/main.rs index 04623c5794..bc2e826b7a 100644 --- a/vm/transaction-benchmarks/src/main.rs +++ b/vm/transaction-benchmarks/src/main.rs @@ -23,8 +23,8 @@ fn main() { default_num_transactions, ); - let acts = [1000]; - let txns = [1000, 10000]; + let acts = [10000]; + let txns = [10000, 50000]; let num_warmups = 2; let num_runs = 10; let num_threads = opt.concurrency_level; From b3e89d43d66fedb415c8f16d79fa997742204f2d Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Mon, 11 Sep 2023 18:27:15 +0800 Subject: [PATCH 27/89] enlarge block size --- scripts/stm_flamegraph.sh | 4 ---- vm/transaction-benchmarks/src/main.rs | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/scripts/stm_flamegraph.sh b/scripts/stm_flamegraph.sh index 98e8946036..c45399b2e0 100755 --- a/scripts/stm_flamegraph.sh +++ b/scripts/stm_flamegraph.sh @@ -10,10 +10,6 @@ cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 2" echo "run tps with cmd: ${cmd}" eval "$cmd" -cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 4" -echo "run tps with cmd: ${cmd}" -eval "$cmd" - cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 8" echo "run tps with cmd: ${cmd}" eval "$cmd" diff --git a/vm/transaction-benchmarks/src/main.rs b/vm/transaction-benchmarks/src/main.rs index bc2e826b7a..e2d455564b 100644 --- a/vm/transaction-benchmarks/src/main.rs +++ b/vm/transaction-benchmarks/src/main.rs @@ -23,8 +23,8 @@ fn main() { default_num_transactions, ); - let acts = [10000]; - let txns = [10000, 50000]; + let acts = [1000]; + let txns = [500000]; let num_warmups = 2; let num_runs = 10; let num_threads = opt.concurrency_level; From 81033659e06957a9cf073d79e4f7ec0151f886d5 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Mon, 11 Sep 2023 21:16:44 +0800 Subject: [PATCH 28/89] add par seq tps info --- scripts/stm_flamegraph.sh | 22 +---- vm/block-executor/src/executor.rs | 6 +- vm/transaction-benchmarks/src/main.rs | 66 ++++++++++--- vm/transaction-benchmarks/src/transactions.rs | 54 ++++++++++ vm/vm-runtime/src/block_executor/mod.rs | 99 +++++++++++++++++++ 5 files changed, 207 insertions(+), 40 deletions(-) diff --git a/scripts/stm_flamegraph.sh b/scripts/stm_flamegraph.sh index c45399b2e0..3512d38c1e 100755 --- a/scripts/stm_flamegraph.sh +++ b/scripts/stm_flamegraph.sh @@ -6,27 +6,7 @@ if [[ "$(uname)" != "Linux" ]]; then echo "run flamegraph only in linux. exit" fi -cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 2" -echo "run tps with cmd: ${cmd}" -eval "$cmd" - -cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 8" -echo "run tps with cmd: ${cmd}" -eval "$cmd" - -cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 12" -echo "run tps with cmd: ${cmd}" -eval "$cmd" - -cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 16" -echo "run tps with cmd: ${cmd}" -eval "$cmd" - -cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 20" -echo "run tps with cmd: ${cmd}" -eval "$cmd" - -cmd="cargo run -p starcoin-transaction-benchmarks --features fuzzing -- -n 24" +cmd="cargo run -p starcoin-transaction-benchmarks --release --features fuzzing -- -n 16" echo "run tps with cmd: ${cmd}" eval "$cmd" diff --git a/vm/block-executor/src/executor.rs b/vm/block-executor/src/executor.rs index e6f16f0017..b54033aca9 100644 --- a/vm/block-executor/src/executor.rs +++ b/vm/block-executor/src/executor.rs @@ -14,7 +14,7 @@ use starcoin_infallible::Mutex; use starcoin_mvhashmap::MVHashMap; use std::{collections::HashSet, hash::Hash, marker::PhantomData, sync::Arc, thread::spawn}; -static RAYON_EXEC_POOL: Lazy = Lazy::new(|| { +pub static RAYON_EXEC_POOL: Lazy = Lazy::new(|| { rayon::ThreadPoolBuilder::new() .num_threads(num_cpus::get()) .thread_name(|index| format!("par_exec_{}", index)) @@ -113,11 +113,11 @@ where T: Transaction, E: ExecutorTask, { - /// The caller needs to ensure that concurrency_level > 1 (0 is illegal and 1 should + /// The caller needs to ensure that concurrency_level >= 1 (0 is illegal and 1 should /// be handled by sequential execution) and that concurrency_level <= num_cpus. pub fn new(concurrency_level: usize) -> Self { assert!( - concurrency_level > 1 && concurrency_level <= num_cpus::get(), + concurrency_level > 0 && concurrency_level <= num_cpus::get(), "Parallel execution concurrency level {} should be between 2 and number of CPUs", concurrency_level ); diff --git a/vm/transaction-benchmarks/src/main.rs b/vm/transaction-benchmarks/src/main.rs index e2d455564b..1eac2327d5 100644 --- a/vm/transaction-benchmarks/src/main.rs +++ b/vm/transaction-benchmarks/src/main.rs @@ -1,21 +1,33 @@ +use clap::Parser; use num_cpus; use proptest::prelude::*; use starcoin_language_e2e_tests::account_universe::P2PTransferGen; use starcoin_transaction_benchmarks::transactions::TransactionBencher; -use clap::Parser; #[derive(Debug, Parser)] -#[clap(name = "concurrency level", about = "concurrency level")] pub struct ConcurrencyLevelOpt { #[clap(long, short = 'n')] /// concurrency level pub concurrency_level: usize, + #[clap(long, short = 'p')] + /// run parallel + pub run_par: bool, + /// run seq + #[clap(long, short = 's')] + pub run_seq: bool, } fn main() { let opt: ConcurrencyLevelOpt = ConcurrencyLevelOpt::parse(); let default_num_accounts = 100; let default_num_transactions = 1_000; + let concurrency_level = opt.concurrency_level; + let mut run_par = opt.run_par; + let run_seq = true; + + if concurrency_level > 0 { + run_par = true; + } let bencher = TransactionBencher::new( any_with::((1_000, 1_000_000)), @@ -24,30 +36,34 @@ fn main() { ); let acts = [1000]; - let txns = [500000]; + let txns = [50000]; let num_warmups = 2; let num_runs = 10; - let num_threads = opt.concurrency_level; println!("num cpus = {}", num_cpus::get()); - let mut measurements = Vec::new(); + let mut par_measurements = Vec::new(); + let mut seq_measurements = Vec::new(); for block_size in txns { for num_accounts in acts { - let mut times = bencher.manual_parallel( + let (mut par_tps, mut seq_tps) = bencher.blockstm_benchmark( num_accounts, block_size, + run_par, + run_seq, num_warmups, num_runs, - num_threads, + concurrency_level, ); - times.sort(); - measurements.push(times); + par_tps.sort(); + seq_tps.sort(); + par_measurements.push(par_tps); + seq_measurements.push(seq_tps); } } - println!("CPUS = {}", num_cpus::get()); + println!("\nconcurrency_level = {}\n", concurrency_level); let mut i = 0; for block_size in txns { @@ -56,13 +72,31 @@ fn main() { "PARAMS: num_account = {}, block_size = {}", num_accounts, block_size ); - println!("TPS: {:?}", measurements[i]); - let mut sum = 0; - for m in &measurements[i] { - sum += m; + + let mut seq_tps = 1; + if run_seq { + println!("Sequential TPS: {:?}", seq_measurements[i]); + let mut seq_sum = 0; + for m in &seq_measurements[i] { + seq_sum += m; + } + seq_tps = seq_sum / seq_measurements[i].len(); + println!("Avg Sequential TPS = {:?}", seq_tps,); + } + + if run_par { + println!("Parallel TPS: {:?}", par_measurements[i]); + let mut par_sum = 0; + for m in &par_measurements[i] { + par_sum += m; + } + let par_tps = par_sum / par_measurements[i].len(); + println!("Avg Parallel TPS = {:?}", par_tps,); + if run_seq { + println!("Speed up {}x over sequential", par_tps / seq_tps); + } } - println!("AVG TPS = {:?}", sum / measurements[i].len()); - i = i + 1; + i += 1; } println!(); } diff --git a/vm/transaction-benchmarks/src/transactions.rs b/vm/transaction-benchmarks/src/transactions.rs index b73d01e961..d351cce185 100644 --- a/vm/transaction-benchmarks/src/transactions.rs +++ b/vm/transaction-benchmarks/src/transactions.rs @@ -100,6 +100,45 @@ where println!("cpu num = {}, cost time = {}", num, use_time.as_secs()); } + /// Runs the bencher. + pub fn blockstm_benchmark( + &self, + num_accounts: usize, + num_txn: usize, + run_par: bool, + run_seq: bool, + num_warmups: usize, + num_runs: usize, + concurrency_level: usize, + ) -> (Vec, Vec) { + let mut par_tps = Vec::new(); + let mut seq_tps = Vec::new(); + + let total_runs = num_warmups + num_runs; + for i in 0..total_runs { + let state = TransactionBenchState::with_size(&self.strategy, num_accounts, num_txn); + + if i < num_warmups { + println!("WARMUP - ignore results"); + state.execute_blockstm_benchmark(concurrency_level, run_par, run_seq); + } else { + println!( + "RUN benchmark for: num_threads = {}, \ + num_account = {}, \ + block_size = {}", + num_cpus::get(), + num_accounts, + num_txn, + ); + let tps = state.execute_blockstm_benchmark(concurrency_level, run_par, run_seq); + par_tps.push(tps.0); + seq_tps.push(tps.1); + } + } + + (par_tps, seq_tps) + } + pub fn manual_sequence( &self, num_accounts: usize, @@ -301,6 +340,21 @@ impl TransactionBenchState { // ) // .expect("VM should not fail to start"); // } + + fn execute_blockstm_benchmark( + self, + concurrency_level: usize, + run_par: bool, + run_seq: bool, + ) -> (usize, usize) { + BlockStarcoinVM::execute_block_benchmark( + self.transactions, + self.executor.get_state_view(), + concurrency_level, + run_par, + run_seq, + ) + } } /// Returns a strategy for the account universe customized for benchmarks. diff --git a/vm/vm-runtime/src/block_executor/mod.rs b/vm/vm-runtime/src/block_executor/mod.rs index 898640fa9b..c2ccf4d2c1 100644 --- a/vm/vm-runtime/src/block_executor/mod.rs +++ b/vm/vm-runtime/src/block_executor/mod.rs @@ -12,6 +12,7 @@ use crate::{ }; use move_core_types::vm_status::{StatusCode, VMStatus}; use rayon::prelude::*; +use starcoin_block_executor::executor::RAYON_EXEC_POOL; use starcoin_block_executor::{ errors::Error, executor::BlockExecutor, @@ -138,4 +139,102 @@ impl BlockStarcoinVM { transactions.len() * 1000 / exec_t.as_millis() as usize } + + pub fn execute_block_benchmark( + transactions: Vec, + state_view: &S, + concurrency_level: usize, + run_par: bool, + run_seq: bool, + ) -> (usize, usize) { + let (par_tps, par_ret) = if run_par { + BlockStarcoinVM::execute_block_benchmark_parallel( + transactions.clone(), + state_view, + concurrency_level, + ) + } else { + (0, None) + }; + let (seq_tps, seq_ret) = if run_seq { + BlockStarcoinVM::execute_block_benchmark_sequential(transactions, state_view) + } else { + (0, None) + }; + + if let (Some(par), Some(seq)) = (par_ret.as_ref(), seq_ret.as_ref()) { + assert_eq!(par, seq); + } + + drop(par_ret); + drop(seq_ret); + + (par_tps, seq_tps) + } + + fn execute_block_benchmark_parallel( + transactions: Vec, + state_view: &S, + concurrency_level: usize, + ) -> ( + usize, + Option, Error>>, + ) { + // Verify the signatures of all the transactions in parallel. + // This is time consuming so don't wait and do the checking + // sequentially while executing the transactions. + let signature_verified_block: Vec = + RAYON_EXEC_POOL.install(|| { + transactions + .clone() + .into_par_iter() + .with_min_len(25) + .map(preprocess_transaction) + .collect() + }); + let block_size = signature_verified_block.len(); + + let executor = + BlockExecutor::>::new(concurrency_level); + println!("Parallel execution starts..."); + let timer = Instant::now(); + let ret = executor.execute_transactions_parallel(state_view, signature_verified_block); + let exec_t = timer.elapsed(); + println!( + "Parallel execution finishes, TPS = {}", + block_size * 1000 / exec_t.as_millis() as usize + ); + let par_ret = ret.map(|results| results.into_iter().map(|output| output.into()).collect()); + ( + block_size * 1000 / exec_t.as_millis() as usize, + Some(par_ret), + ) + } + + fn execute_block_benchmark_sequential( + transactions: Vec, + state_view: &S, + ) -> ( + usize, + Option, Error>>, + ) { + // Verify the signatures of all the transactions in parallel. + // This is time consuming so don't wait and do the checking + // sequentially while executing the transactions. + + let block_size = transactions.len(); + + // sequentially execute the block and check if the results match + println!("Sequential execution starts..."); + let seq_timer = Instant::now(); + let mut vm = StarcoinVM::new(None); + let ret = vm.execute_block_transactions(state_view, transactions, None); + let seq_exec_t = seq_timer.elapsed(); + println!( + "Sequential execution finishes, TPS = {}", + block_size * 1000 / seq_exec_t.as_millis() as usize + ); + + (block_size * 1000 / seq_exec_t.as_millis() as usize, None) + } } From efbadd8f56526fb0f1bcf95bde49a10268f3899e Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Mon, 11 Sep 2023 22:23:26 +0800 Subject: [PATCH 29/89] update concurrency_level 32 --- scripts/stm_flamegraph.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/stm_flamegraph.sh b/scripts/stm_flamegraph.sh index 3512d38c1e..e0e17a2a0d 100755 --- a/scripts/stm_flamegraph.sh +++ b/scripts/stm_flamegraph.sh @@ -6,10 +6,10 @@ if [[ "$(uname)" != "Linux" ]]; then echo "run flamegraph only in linux. exit" fi -cmd="cargo run -p starcoin-transaction-benchmarks --release --features fuzzing -- -n 16" +cmd="cargo run -p starcoin-transaction-benchmarks --release --features fuzzing -- -n 32" echo "run tps with cmd: ${cmd}" eval "$cmd" -cmd="cargo bench -p starcoin-transaction-benchmarks --bench transaction_benches --features fuzzing,flamegraph -- --profile-time=20" +cmd="cargo bench -p starcoin-transaction-benchmarks --release --bench transaction_benches --features fuzzing,flamegraph -- --profile-time=20" echo "run flamegraph with cmd: ${cmd}" eval "$cmd" From b338d9993f574272c1b4fb6e071834642962f614 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Mon, 11 Sep 2023 22:40:25 +0800 Subject: [PATCH 30/89] update txn size 80000 --- scripts/stm_flamegraph.sh | 4 ++-- vm/transaction-benchmarks/src/main.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/stm_flamegraph.sh b/scripts/stm_flamegraph.sh index e0e17a2a0d..413be4b446 100755 --- a/scripts/stm_flamegraph.sh +++ b/scripts/stm_flamegraph.sh @@ -6,10 +6,10 @@ if [[ "$(uname)" != "Linux" ]]; then echo "run flamegraph only in linux. exit" fi -cmd="cargo run -p starcoin-transaction-benchmarks --release --features fuzzing -- -n 32" +cmd="cargo run -p starcoin-transaction-benchmarks --release --features fuzzing -- -n 24" echo "run tps with cmd: ${cmd}" eval "$cmd" -cmd="cargo bench -p starcoin-transaction-benchmarks --release --bench transaction_benches --features fuzzing,flamegraph -- --profile-time=20" +cmd="cargo bench -p starcoin-transaction-benchmarks --bench transaction_benches --features fuzzing,flamegraph -- --profile-time=20" echo "run flamegraph with cmd: ${cmd}" eval "$cmd" diff --git a/vm/transaction-benchmarks/src/main.rs b/vm/transaction-benchmarks/src/main.rs index 1eac2327d5..7f6583d71c 100644 --- a/vm/transaction-benchmarks/src/main.rs +++ b/vm/transaction-benchmarks/src/main.rs @@ -36,7 +36,7 @@ fn main() { ); let acts = [1000]; - let txns = [50000]; + let txns = [80000]; let num_warmups = 2; let num_runs = 10; From 80bf293802dd7b1ffbd0a092de71c8208b215911 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Mon, 11 Sep 2023 22:53:17 +0800 Subject: [PATCH 31/89] update txn size 100k --- scripts/stm_flamegraph.sh | 2 +- vm/transaction-benchmarks/src/main.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/stm_flamegraph.sh b/scripts/stm_flamegraph.sh index 413be4b446..fa606fd500 100755 --- a/scripts/stm_flamegraph.sh +++ b/scripts/stm_flamegraph.sh @@ -6,7 +6,7 @@ if [[ "$(uname)" != "Linux" ]]; then echo "run flamegraph only in linux. exit" fi -cmd="cargo run -p starcoin-transaction-benchmarks --release --features fuzzing -- -n 24" +cmd="cargo run -p starcoin-transaction-benchmarks --release --features fuzzing -- -n 32" echo "run tps with cmd: ${cmd}" eval "$cmd" diff --git a/vm/transaction-benchmarks/src/main.rs b/vm/transaction-benchmarks/src/main.rs index 7f6583d71c..a9f0849705 100644 --- a/vm/transaction-benchmarks/src/main.rs +++ b/vm/transaction-benchmarks/src/main.rs @@ -36,7 +36,7 @@ fn main() { ); let acts = [1000]; - let txns = [80000]; + let txns = [100000]; let num_warmups = 2; let num_runs = 10; From 43f67a5349b1476b3ae64cd2a90898a21583b46c Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Mon, 11 Sep 2023 23:10:02 +0800 Subject: [PATCH 32/89] fix print info --- vm/transaction-benchmarks/src/transactions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/transaction-benchmarks/src/transactions.rs b/vm/transaction-benchmarks/src/transactions.rs index d351cce185..34da56e928 100644 --- a/vm/transaction-benchmarks/src/transactions.rs +++ b/vm/transaction-benchmarks/src/transactions.rs @@ -126,7 +126,7 @@ where "RUN benchmark for: num_threads = {}, \ num_account = {}, \ block_size = {}", - num_cpus::get(), + concurrency_level, num_accounts, num_txn, ); From 1a4e540abab5cd2491997bf717c542da6f2aa456 Mon Sep 17 00:00:00 2001 From: welbon Date: Tue, 12 Sep 2023 15:19:26 +0800 Subject: [PATCH 33/89] [benchmark] append txn numbers and concurrecy level as command line --- vm/transaction-benchmarks/src/main.rs | 59 +++++++++++++++------------ 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/vm/transaction-benchmarks/src/main.rs b/vm/transaction-benchmarks/src/main.rs index a9f0849705..7842b9301b 100644 --- a/vm/transaction-benchmarks/src/main.rs +++ b/vm/transaction-benchmarks/src/main.rs @@ -6,9 +6,12 @@ use starcoin_transaction_benchmarks::transactions::TransactionBencher; #[derive(Debug, Parser)] pub struct ConcurrencyLevelOpt { - #[clap(long, short = 'n')] + #[clap(long, short = 'n', use_delimiter = true)] /// concurrency level - pub concurrency_level: usize, + pub concurrency_level: Vec, + #[clap(long, short = 't', use_delimiter = true)] + /// Transaction numbers + pub txn_nums: Vec, #[clap(long, short = 'p')] /// run parallel pub run_par: bool, @@ -21,13 +24,17 @@ fn main() { let opt: ConcurrencyLevelOpt = ConcurrencyLevelOpt::parse(); let default_num_accounts = 100; let default_num_transactions = 1_000; - let concurrency_level = opt.concurrency_level; + let concurrency_levels = opt.concurrency_level; + let txns = opt.txn_nums; let mut run_par = opt.run_par; let run_seq = true; - if concurrency_level > 0 { - run_par = true; - } + assert!(!concurrency_levels.is_empty(), "Concurrcy level array is empty!"); + assert!(!txns.is_empty(), "Transaction numbers level array is empty!"); + + // if !concurrency_levels.is_empty() { + // run_par = true; + // } let bencher = TransactionBencher::new( any_with::((1_000, 1_000_000)), @@ -36,7 +43,7 @@ fn main() { ); let acts = [1000]; - let txns = [100000]; + //let txns = [10000, 50000, 100000]; let num_warmups = 2; let num_runs = 10; @@ -45,32 +52,34 @@ fn main() { let mut par_measurements = Vec::new(); let mut seq_measurements = Vec::new(); - for block_size in txns { - for num_accounts in acts { - let (mut par_tps, mut seq_tps) = bencher.blockstm_benchmark( - num_accounts, - block_size, - run_par, - run_seq, - num_warmups, - num_runs, - concurrency_level, - ); - par_tps.sort(); - seq_tps.sort(); - par_measurements.push(par_tps); - seq_measurements.push(seq_tps); + for concurrency_level in concurrency_levels { + for block_size in &txns { + for num_accounts in acts { + let (mut par_tps, mut seq_tps) = bencher.blockstm_benchmark( + num_accounts, + *block_size, + run_par || (concurrency_level > 1), + run_seq, + num_warmups, + num_runs, + concurrency_level, + ); + par_tps.sort(); + seq_tps.sort(); + par_measurements.push(par_tps); + seq_measurements.push(seq_tps); + } } + println!("\nconcurrency_level = {}\n", concurrency_level); } - println!("\nconcurrency_level = {}\n", concurrency_level); let mut i = 0; - for block_size in txns { + for block_size in &txns { for num_accounts in acts { println!( "PARAMS: num_account = {}, block_size = {}", - num_accounts, block_size + num_accounts, *block_size ); let mut seq_tps = 1; From cf99123990b39b48ac0ded40f1093cdd8ec5db11 Mon Sep 17 00:00:00 2001 From: welbon Date: Tue, 12 Sep 2023 15:44:10 +0800 Subject: [PATCH 34/89] [benchmark] append txn numbers and concurrecy level as command line into bash scripts --- scripts/benchmark_parallel.sh | 43 +++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/scripts/benchmark_parallel.sh b/scripts/benchmark_parallel.sh index 7b18eb66e4..ab0ff54fd6 100755 --- a/scripts/benchmark_parallel.sh +++ b/scripts/benchmark_parallel.sh @@ -1,2 +1,41 @@ -RUST_LOG=info cargo bench --features fuzzing -p 'starcoin-block-executor' -RUST_LOG=info cargo bench --features fuzzing -p 'starcoin-transaction-benchmarks' \ No newline at end of file + +#RUST_LOG=info cargo bench --features fuzzing -p 'starcoin-block-executor' +#RUST_LOG=info cargo bench --features fuzzing -p 'starcoin-transaction-benchmarks' + +STARCOIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd .. && pwd)" +TXN_NUMS=10000,50000,100000 + +if [[ "$OSTYPE" == "linux-gnu"* ]]; then + # Linux + physical_cores=$(lscpu -p=CPU,Core,Socket | grep -v '#' | sort -u -t, -k2,3 | wc -l) +elif [[ "$OSTYPE" == "darwin"* ]]; then + # macOS + physical_cores=$(sysctl -n hw.physicalcpu) +else + echo "Unknown OS" + exit 1 +fi + +# 创建一个数组来存储每个核心的模 2 值 +declare -a power_of_two_array + +if (( physical_cores <= 4 )); then + power_of_two_array=(1 2 4) +else + current_power=4 + while (( current_power <= physical_cores )); do + power_of_two_array+=($current_power) + current_power=$((current_power * 2)) + done + + if ! [[ " ${power_of_two_array[@]} " =~ " ${physical_cores} " ]]; then + power_of_two_array+=($physical_cores) + fi +fi + +# 打印数组 +IFS=',' +power_of_two_str="${power_of_two_array[*]}" + +#echo "Power of two array: ${power_of_two_str[@]}" +eval RUST_LOG=info cargo run --release -p "starcoin-transaction-benchmarks" --features fuzzing -- --concurrency-level "$power_of_two_str" --txn-nums "$TXN_NUMS" \ No newline at end of file From 2bd2cc0c0349736454f64042b1ec46662574e64d Mon Sep 17 00:00:00 2001 From: welbon Date: Tue, 12 Sep 2023 16:30:12 +0800 Subject: [PATCH 35/89] [benchmark] fixed error of summary --- vm/transaction-benchmarks/src/main.rs | 84 +++++++++++++-------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/vm/transaction-benchmarks/src/main.rs b/vm/transaction-benchmarks/src/main.rs index 7842b9301b..f6c3f9b7f2 100644 --- a/vm/transaction-benchmarks/src/main.rs +++ b/vm/transaction-benchmarks/src/main.rs @@ -30,7 +30,7 @@ fn main() { let run_seq = true; assert!(!concurrency_levels.is_empty(), "Concurrcy level array is empty!"); - assert!(!txns.is_empty(), "Transaction numbers level array is empty!"); + assert!(!txns.is_empty(), "Transaction numbers level array is empty!"); // if !concurrency_levels.is_empty() { // run_par = true; @@ -47,66 +47,66 @@ fn main() { let num_warmups = 2; let num_runs = 10; - println!("num cpus = {}", num_cpus::get()); + println!("num cpus = {}, run_seq: {}", num_cpus::get(), run_seq); - let mut par_measurements = Vec::new(); - let mut seq_measurements = Vec::new(); + for concurrency_level in &concurrency_levels { + let mut par_measurements = Vec::new(); + let mut seq_measurements = Vec::new(); - for concurrency_level in concurrency_levels { - for block_size in &txns { - for num_accounts in acts { + for num_accounts in acts { + println!("\n========== concurrency_level: {} started ==========\n ", concurrency_level); + for block_size in &txns { let (mut par_tps, mut seq_tps) = bencher.blockstm_benchmark( num_accounts, *block_size, - run_par || (concurrency_level > 1), + run_par || (*concurrency_level > 1), run_seq, num_warmups, num_runs, - concurrency_level, + *concurrency_level, ); par_tps.sort(); seq_tps.sort(); par_measurements.push(par_tps); seq_measurements.push(seq_tps); } - } - println!("\nconcurrency_level = {}\n", concurrency_level); - } - + println!("\n========== concurrency_level: {} completed ========== \n", concurrency_level); - let mut i = 0; - for block_size in &txns { - for num_accounts in acts { - println!( - "PARAMS: num_account = {}, block_size = {}", - num_accounts, *block_size - ); + let mut i = 0; + for block_size in &txns { + for num_accounts in acts { + println!( + "PARAMS: num_account = {}, block_size = {}", + num_accounts, *block_size + ); - let mut seq_tps = 1; - if run_seq { - println!("Sequential TPS: {:?}", seq_measurements[i]); - let mut seq_sum = 0; - for m in &seq_measurements[i] { - seq_sum += m; - } - seq_tps = seq_sum / seq_measurements[i].len(); - println!("Avg Sequential TPS = {:?}", seq_tps,); - } + let mut seq_tps = 1; + if run_seq { + println!("Sequential TPS: {:?}", seq_measurements[i]); + let mut seq_sum = 0; + for m in &seq_measurements[i] { + seq_sum += m; + } + seq_tps = seq_sum / seq_measurements[i].len(); + println!("Avg Sequential TPS = {:?}", seq_tps, ); + } - if run_par { - println!("Parallel TPS: {:?}", par_measurements[i]); - let mut par_sum = 0; - for m in &par_measurements[i] { - par_sum += m; - } - let par_tps = par_sum / par_measurements[i].len(); - println!("Avg Parallel TPS = {:?}", par_tps,); - if run_seq { - println!("Speed up {}x over sequential", par_tps / seq_tps); + if run_par { + println!("Parallel TPS: {:?}", par_measurements[i]); + let mut par_sum = 0; + for m in &par_measurements[i] { + par_sum += m; + } + let par_tps = par_sum / par_measurements[i].len(); + println!("Avg Parallel TPS = {:?}", par_tps, ); + if run_seq { + println!("Speed up {}x over sequential", par_tps / seq_tps); + } + } + i += 1; } + println!(); } - i += 1; } - println!(); } } From 77c741638a87bb34c598b72ea2c1628a2daaf7e4 Mon Sep 17 00:00:00 2001 From: welbon Date: Tue, 12 Sep 2023 16:36:42 +0800 Subject: [PATCH 36/89] [benchmark] fixed error of summary --- vm/transaction-benchmarks/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vm/transaction-benchmarks/src/main.rs b/vm/transaction-benchmarks/src/main.rs index f6c3f9b7f2..946a5dcf49 100644 --- a/vm/transaction-benchmarks/src/main.rs +++ b/vm/transaction-benchmarks/src/main.rs @@ -12,11 +12,11 @@ pub struct ConcurrencyLevelOpt { #[clap(long, short = 't', use_delimiter = true)] /// Transaction numbers pub txn_nums: Vec, - #[clap(long, short = 'p')] + #[clap(long, short = 'p', parse(try_from_str), default_value = "true")] /// run parallel pub run_par: bool, /// run seq - #[clap(long, short = 's')] + #[clap(long, short = 's', parse(try_from_str), default_value = "true")] pub run_seq: bool, } @@ -47,7 +47,7 @@ fn main() { let num_warmups = 2; let num_runs = 10; - println!("num cpus = {}, run_seq: {}", num_cpus::get(), run_seq); + println!("num cpus = {}, run_seq: {}, run_seq: {}", num_cpus::get(), run_seq, run_seq); for concurrency_level in &concurrency_levels { let mut par_measurements = Vec::new(); From ab99a8cf853863d3f918162c40cdafcfeb6bc3b0 Mon Sep 17 00:00:00 2001 From: welbon Date: Tue, 19 Sep 2023 14:49:32 +0800 Subject: [PATCH 37/89] [benchmark] add command line support benchmark for account number --- scripts/benchmark_parallel.sh | 5 +- vm/transaction-benchmarks/src/main.rs | 86 ++++++++++++++++----------- 2 files changed, 53 insertions(+), 38 deletions(-) diff --git a/scripts/benchmark_parallel.sh b/scripts/benchmark_parallel.sh index ab0ff54fd6..50d973108e 100755 --- a/scripts/benchmark_parallel.sh +++ b/scripts/benchmark_parallel.sh @@ -3,7 +3,8 @@ #RUST_LOG=info cargo bench --features fuzzing -p 'starcoin-transaction-benchmarks' STARCOIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd .. && pwd)" -TXN_NUMS=10000,50000,100000 +TXN_NUMS=100000 +ACCOUNT_NUMS=2,10,100 if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux @@ -38,4 +39,4 @@ IFS=',' power_of_two_str="${power_of_two_array[*]}" #echo "Power of two array: ${power_of_two_str[@]}" -eval RUST_LOG=info cargo run --release -p "starcoin-transaction-benchmarks" --features fuzzing -- --concurrency-level "$power_of_two_str" --txn-nums "$TXN_NUMS" \ No newline at end of file +eval RUST_LOG=info cargo run --release -p "starcoin-transaction-benchmarks" --features fuzzing -- --concurrency-level "$power_of_two_str" --txn-nums "$TXN_NUMS" --account-nums="$ACCOUNT_NUMS" \ No newline at end of file diff --git a/vm/transaction-benchmarks/src/main.rs b/vm/transaction-benchmarks/src/main.rs index 946a5dcf49..7ef1fa716c 100644 --- a/vm/transaction-benchmarks/src/main.rs +++ b/vm/transaction-benchmarks/src/main.rs @@ -6,15 +6,22 @@ use starcoin_transaction_benchmarks::transactions::TransactionBencher; #[derive(Debug, Parser)] pub struct ConcurrencyLevelOpt { - #[clap(long, short = 'n', use_delimiter = true)] /// concurrency level + #[clap(long, short = 'n', use_delimiter = true)] pub concurrency_level: Vec, - #[clap(long, short = 't', use_delimiter = true)] + /// Transaction numbers + #[clap(long, short = 't', use_delimiter = true)] pub txn_nums: Vec, - #[clap(long, short = 'p', parse(try_from_str), default_value = "true")] + + /// Account numbers + #[clap(long, short = 'a', use_delimiter = true)] + pub account_nums: Vec, + /// run parallel + #[clap(long, short = 'p', parse(try_from_str), default_value = "true")] pub run_par: bool, + /// run seq #[clap(long, short = 's', parse(try_from_str), default_value = "true")] pub run_seq: bool, @@ -26,11 +33,13 @@ fn main() { let default_num_transactions = 1_000; let concurrency_levels = opt.concurrency_level; let txns = opt.txn_nums; + let account_nums = opt.account_nums; let mut run_par = opt.run_par; let run_seq = true; assert!(!concurrency_levels.is_empty(), "Concurrcy level array is empty!"); assert!(!txns.is_empty(), "Transaction numbers level array is empty!"); + assert!(!account_nums.is_empty(), "Transaction numbers level array is empty!"); // if !concurrency_levels.is_empty() { // run_par = true; @@ -42,7 +51,8 @@ fn main() { default_num_transactions, ); - let acts = [1000]; + + // let acts = [1000]; //let txns = [10000, 50000, 100000]; let num_warmups = 2; let num_runs = 10; @@ -53,11 +63,13 @@ fn main() { let mut par_measurements = Vec::new(); let mut seq_measurements = Vec::new(); - for num_accounts in acts { - println!("\n========== concurrency_level: {} started ==========\n ", concurrency_level); + println!("=========== concurrency_level: {} started ===========", concurrency_level); + + for num_accounts in &account_nums { + println!("=== accounts_num: {} started ===", num_accounts); for block_size in &txns { let (mut par_tps, mut seq_tps) = bencher.blockstm_benchmark( - num_accounts, + *num_accounts, *block_size, run_par || (*concurrency_level > 1), run_seq, @@ -70,43 +82,45 @@ fn main() { par_measurements.push(par_tps); seq_measurements.push(seq_tps); } - println!("\n========== concurrency_level: {} completed ========== \n", concurrency_level); + println!("=== accounts_num: {} completed ===", num_accounts); + } - let mut i = 0; + let mut i = 0; + for num_accounts in &account_nums { for block_size in &txns { - for num_accounts in acts { - println!( - "PARAMS: num_account = {}, block_size = {}", - num_accounts, *block_size - ); + println!( + "PARAMS: num_account = {}, block_size = {}", + *num_accounts, *block_size + ); - let mut seq_tps = 1; - if run_seq { - println!("Sequential TPS: {:?}", seq_measurements[i]); - let mut seq_sum = 0; - for m in &seq_measurements[i] { - seq_sum += m; - } - seq_tps = seq_sum / seq_measurements[i].len(); - println!("Avg Sequential TPS = {:?}", seq_tps, ); + let mut seq_tps = 0; + let seq_measurement = &seq_measurements[i]; + let par_measurement = &par_measurements[i]; + if run_seq { + println!("Sequential TPS: {:?}", seq_measurement); + let mut seq_sum = 0; + for m in seq_measurement { + seq_sum += m; } + seq_tps = seq_sum / seq_measurement.len(); + println!("Avg Sequential TPS = {:?}", seq_tps, ); + } - if run_par { - println!("Parallel TPS: {:?}", par_measurements[i]); - let mut par_sum = 0; - for m in &par_measurements[i] { - par_sum += m; - } - let par_tps = par_sum / par_measurements[i].len(); - println!("Avg Parallel TPS = {:?}", par_tps, ); - if run_seq { - println!("Speed up {}x over sequential", par_tps / seq_tps); - } + if run_par { + println!("Parallel TPS: {:?}", par_measurement); + let mut par_sum = 0; + for m in &par_measurements[i] { + par_sum += m; + } + let par_tps = par_sum / par_measurement.len(); + println!("Avg Parallel TPS = {:?}", par_tps, ); + if run_seq { + println!("Speed up {}x over sequential", par_tps / seq_tps); } - i += 1; } - println!(); + i += 1; } } + println!("=========== concurrency_level: {} finished ===========", concurrency_level); } } From 6023dd138e7f475e854b43ddccc8086155f7e6c3 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Tue, 19 Sep 2023 16:53:05 +0800 Subject: [PATCH 38/89] update build and test ci --- .github/workflows/build_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 5e23b3f457..19642f7200 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -22,7 +22,7 @@ jobs: with: command: clean - name: run flamegraph - run: bash ./scripts/stm_flamegraph.sh + run: bash ./scripts/benchmark_parallel.sh env: RUST_LOG: error RUST_BACKTRACE: full From 2645b433663bd60d6826d90e0b43c4112ec66512 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Tue, 19 Sep 2023 17:26:57 +0800 Subject: [PATCH 39/89] update build and test ci TXN_NUMS 1000 --- scripts/benchmark_parallel.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/benchmark_parallel.sh b/scripts/benchmark_parallel.sh index 50d973108e..93439ec780 100755 --- a/scripts/benchmark_parallel.sh +++ b/scripts/benchmark_parallel.sh @@ -3,7 +3,7 @@ #RUST_LOG=info cargo bench --features fuzzing -p 'starcoin-transaction-benchmarks' STARCOIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd .. && pwd)" -TXN_NUMS=100000 +TXN_NUMS=1000 ACCOUNT_NUMS=2,10,100 if [[ "$OSTYPE" == "linux-gnu"* ]]; then From bce62909396ab4739e5c9c1ef5b0d724388cb784 Mon Sep 17 00:00:00 2001 From: welbon Date: Tue, 19 Sep 2023 18:26:50 +0800 Subject: [PATCH 40/89] [benchmark] Add the case of parallel benchmark --- scripts/benchmark_parallel.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/benchmark_parallel.sh b/scripts/benchmark_parallel.sh index 93439ec780..5c15afe5a2 100755 --- a/scripts/benchmark_parallel.sh +++ b/scripts/benchmark_parallel.sh @@ -3,8 +3,8 @@ #RUST_LOG=info cargo bench --features fuzzing -p 'starcoin-transaction-benchmarks' STARCOIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd .. && pwd)" -TXN_NUMS=1000 -ACCOUNT_NUMS=2,10,100 +TXN_NUMS=1000,10000,50000,100000 +ACCOUNT_NUMS=2,10,100,1000,10000 if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux From 092d2af382bcdc8d389555e73e488f3f51860510 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Tue, 26 Sep 2023 09:52:52 +0800 Subject: [PATCH 41/89] fixed account layout for e2e-test --- vm/e2e-tests/Cargo.toml | 10 - vm/e2e-tests/src/account.rs | 417 ++++++++++++------ vm/e2e-tests/src/account_universe.rs | 2 +- .../src/account_universe/create_account.rs | 2 +- .../src/account_universe/peer_to_peer.rs | 1 + vm/e2e-tests/src/common_transactions.rs | 17 +- vm/e2e-tests/src/data_store.rs | 6 +- vm/e2e-tests/src/executor.rs | 14 +- vm/e2e-tests/src/gas_costs.rs | 10 +- vm/e2e-tests/src/proptest_types.rs | 2 +- vm/transaction-benchmarks/src/transactions.rs | 2 +- vm/vm-runtime/src/block_executor/mod.rs | 2 +- 12 files changed, 311 insertions(+), 174 deletions(-) diff --git a/vm/e2e-tests/Cargo.toml b/vm/e2e-tests/Cargo.toml index d8f9a25fd1..51eaaa7a56 100644 --- a/vm/e2e-tests/Cargo.toml +++ b/vm/e2e-tests/Cargo.toml @@ -39,13 +39,3 @@ move-table-extension = { workspace = true } starcoin-statedb = { workspace = true } starcoin-state-tree = { workspace = true } -#aptos-keygen = { path = "../../crates/aptos-keygen" } -#aptos-proptest-helpers = { path = "../../crates/aptos-proptest-helpers" } -#aptos-state-view = { path = "../../storage/state-view" } -#aptos-transaction-builder = { path = "../../sdk/transaction-builder" } -#aptos-types = { path = "../../types", features = ["fuzzing"] } -#aptos-vm = { path = "../aptos-vm" } -# aptos-writeset-generator = { path = "../writeset-transaction-generator" } -# cached-framework-packages = { path = "../framework/cached-packages" } -# move-deps = { path = "../move-deps", features = ["address32"] } -# vm-genesis = { path = "../vm-genesis" } diff --git a/vm/e2e-tests/src/account.rs b/vm/e2e-tests/src/account.rs index 4eeb3bfe77..e79a25d251 100644 --- a/vm/e2e-tests/src/account.rs +++ b/vm/e2e-tests/src/account.rs @@ -7,44 +7,56 @@ use crate::gas_costs; use anyhow::{Error, Result}; use starcoin_crypto::ed25519::{Ed25519PrivateKey, Ed25519PublicKey}; use starcoin_crypto::keygen::KeyGen; +use starcoin_crypto::ValidCryptoMaterial; +use starcoin_types::account::{Balance, EventHandleGenerator}; use starcoin_vm_types::access_path::AccessPath; use starcoin_vm_types::account_address::AccountAddress; +use starcoin_vm_types::account_config; use starcoin_vm_types::account_config::{genesis_address, AccountResource, BalanceResource}; use starcoin_vm_types::event::EventHandle; use starcoin_vm_types::genesis_config::ChainId; use starcoin_vm_types::language_storage::StructTag; use starcoin_vm_types::move_resource::MoveResource; use starcoin_vm_types::state_store::state_key::StateKey; -use starcoin_vm_types::transaction::authenticator::AuthenticationKey; +use starcoin_vm_types::token::token_code::TokenCode; +use starcoin_vm_types::transaction::authenticator::{ + AccountPrivateKey, AccountPublicKey +}; use starcoin_vm_types::transaction::{ RawUserTransaction, Script, ScriptFunction, SignedUserTransaction, TransactionPayload, }; use starcoin_vm_types::value::{MoveStructLayout, MoveTypeLayout}; use starcoin_vm_types::values::{Struct, Value}; use starcoin_vm_types::write_set::{WriteOp, WriteSet, WriteSetMut}; +use std::collections::BTreeMap; use std::str::FromStr; +use std::sync::Arc; // TTL is 86400s. Initial time was set to 0. pub const DEFAULT_EXPIRATION_TIME: u64 = 40_000; -/// Details about a Aptos account. +pub const STC_TOKEN_CODE_STR: &str = "0x1::STC::STC"; + +/// Details about a Starcoin account. /// /// Tests will typically create a set of `Account` instances to run transactions on. This type -/// encodes the logic to operate on and verify operations on any Aptos account. +/// encodes the logic to operate on and verify operations on any Starcoin account. #[derive(Debug, Clone, Eq, PartialEq)] pub struct Account { - addr: AccountAddress, - /// The current private key for this account. - pub privkey: Ed25519PrivateKey, - /// The current public key for this account. - pub pubkey: Ed25519PublicKey, + // addr: AccountAddress, + // /// The current private key for this account. + // pub privkey: Ed25519PrivateKey, + // /// The current public key for this account. + // pub pubkey: Ed25519PublicKey, + pub addr: AccountAddress, + private_key: Arc, } impl Account { /// Creates a new account in memory. /// /// The account returned by this constructor is a purely logical entity, meaning that it does - /// not automatically get added to the Aptos store. To add an account to the store, use + /// not automatically get added to the Starcoin store. To add an account to the store, use /// [`AccountData`] instances with /// [`FakeExecutor::add_account_data`][crate::executor::FakeExecutor::add_account_data]. /// This function returns distinct values upon every call. @@ -67,11 +79,22 @@ impl Account { let addr = starcoin_vm_types::account_address::from_public_key(&pubkey); Account { addr, - privkey, - pubkey, + private_key: Arc::new(AccountPrivateKey::Single(privkey)), + // pubkey, } } + /// Get the Key pair + pub fn ed25519_key_pair(&self) -> (Ed25519PublicKey, Ed25519PrivateKey) { + ( + self.private_key.public_key().as_single().unwrap(), + match self.private_key.as_ref() { + AccountPrivateKey::Single(pk) => pk.clone(), + AccountPrivateKey::Multi(pk) => pk.private_keys().get(0).unwrap().clone(), + }, + ) + } + /// Creates a new account with the given addr and key pair /// /// Like with [`Account::new`], the account returned by this constructor is a purely logical @@ -79,12 +102,12 @@ impl Account { pub fn new_validator( addr: AccountAddress, privkey: Ed25519PrivateKey, - pubkey: Ed25519PublicKey, + _pubkey: Ed25519PublicKey, ) -> Self { Account { addr, - privkey, - pubkey, + private_key: Arc::new(AccountPrivateKey::Single(privkey)), + // pubkey, } } @@ -98,11 +121,10 @@ impl Account { // pubkey: GENESIS_KEYPAIR.1.clone(), // privkey: GENESIS_KEYPAIR.0.clone(), // } - let (privkey, pubkey) = KeyGen::from_os_rng().generate_keypair(); + let (privkey, _pubkey) = KeyGen::from_os_rng().generate_keypair(); Account { addr: address, - pubkey, - privkey, + private_key: Arc::new(AccountPrivateKey::Single(privkey)), } } @@ -122,20 +144,17 @@ impl Account { &self.addr } - /// Returns the AccessPath that describes the Account resource instance. - /// - /// Use this to retrieve or publish the Account blob. - pub fn make_account_access_path(&self) -> AccessPath { - self.make_access_path(AccountResource::struct_tag()) - } - - /// Returns the AccessPath that describes the Account's CoinStore resource instance. + /// Returns the AccessPath that describes the Account balance resource instance. /// - /// Use this to retrieve or publish the Account CoinStore blob. - pub fn make_coin_store_access_path(&self) -> AccessPath { - // TODO(BobOng): - // self.make_access_path(CoinStoreResource::struct_tag()) - self.make_access_path(BalanceResource::struct_tag()) + /// Use this to retrieve or publish the Account balance blob. + pub fn make_balance_access_path(&self, token_code_str: &str) -> AccessPath { + let token_code = + TokenCode::from_str(token_code_str).expect("token code str should been valid."); + let token_type_tag = token_code + .try_into() + .expect("token code to type tag should be ok"); + // TODO/XXX: Convert this to BalanceResource::struct_tag once that takes type args + self.make_access_path(BalanceResource::struct_tag_for_token(token_type_tag)) } // TODO: plug in the account type @@ -145,22 +164,60 @@ impl Account { AccessPath::resource_access_path(self.addr, tag) } + pub fn make_account_access_path(&self) -> AccessPath { + self.make_access_path(AccountResource::struct_tag()) + } + + /// Returns the AccessPath that describes the EventHandleGenerator resource instance. + /// + /// Use this to retrieve or publish the EventHandleGenerator blob. + pub fn make_event_generator_access_path(&self) -> AccessPath { + self.make_access_path(account_config::event_handle_generator_struct_tag()) + } + /// Changes the keys for this account to the provided ones. - pub fn rotate_key(&mut self, privkey: Ed25519PrivateKey, pubkey: Ed25519PublicKey) { - self.privkey = privkey; - self.pubkey = pubkey; + pub fn rotate_key(&mut self, privkey: Ed25519PrivateKey, _pubkey: Ed25519PublicKey) { + // self.privkey = privkey; + // self.pubkey = pubkey; + self.private_key = Arc::new(AccountPrivateKey::Single(privkey)); } /// Computes the authentication key for this account, as stored on the chain. /// /// This is the same as the account's address if the keys have never been rotated. pub fn auth_key(&self) -> Vec { - AuthenticationKey::ed25519(&self.pubkey).to_vec() + self.private_key.public_key().authentication_key().to_vec() + } + + pub fn public_key(&self) -> Ed25519PublicKey { + match self.private_key.as_ref() { + AccountPrivateKey::Single(k) => Ed25519PublicKey::from(k), + AccountPrivateKey::Multi(k) => k.public_key().public_keys().get(0).unwrap().clone(), + } + } + + pub fn private_key(&self) -> &AccountPrivateKey { + &self.private_key } pub fn transaction(&self) -> TransactionBuilder { TransactionBuilder::new(self.clone()) } + + pub fn account_keypair(&self) -> (AccountPublicKey, AccountPrivateKey) { + let (pub_key, priv_key) = self.ed25519_key_pair(); + ( + AccountPublicKey::Single(pub_key), + AccountPrivateKey::Single(priv_key), + ) + } + + pub fn public_key_bytes(&self) -> Vec { + match self.private_key.as_ref() { + AccountPrivateKey::Single(public_key) => public_key.to_bytes().to_vec(), + AccountPrivateKey::Multi(public_key) => public_key.to_bytes().to_vec(), + } + } } impl Default for Account { @@ -263,6 +320,7 @@ impl TransactionBuilder { } pub fn sign(self) -> SignedUserTransaction { + let (public_key, private_key) = self.sender.ed25519_key_pair(); RawUserTransaction::new_with_default_gas_token( *self.sender.address(), self.sequence_number.expect("sequence number not set"), @@ -272,7 +330,7 @@ impl TransactionBuilder { self.ttl.unwrap_or(DEFAULT_EXPIRATION_TIME), self.chain_id.unwrap_or_else(ChainId::test), ) - .sign(&self.sender.privkey, self.sender.pubkey) + .sign(&private_key, public_key) .unwrap() .into_inner() } @@ -307,64 +365,64 @@ impl TransactionBuilder { // .into_inner() // } } - -//--------------------------------------------------------------------------- -// CoinStore resource represenation -//--------------------------------------------------------------------------- - -/// Struct that represents an account CoinStore resource for tests. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct CoinStore { - coin: u64, - deposit_events: EventHandle, - withdraw_events: EventHandle, -} - -impl CoinStore { - /// Create a new CoinStore - pub fn new(coin: u64, deposit_events: EventHandle, withdraw_events: EventHandle) -> Self { - Self { - coin, - deposit_events, - withdraw_events, - } - } - - /// Retrieve the balance inside of this - pub fn coin(&self) -> u64 { - self.coin - } - - /// Returns the Move Value for the account's CoinStore - pub fn to_value(&self) -> Value { - Value::struct_(Struct::pack(vec![ - Value::u64(self.coin), - Value::struct_(Struct::pack(vec![ - Value::u64(self.withdraw_events.count()), - Value::vector_u8(self.withdraw_events.key().to_vec()), - ])), - Value::struct_(Struct::pack(vec![ - Value::u64(self.deposit_events.count()), - Value::vector_u8(self.deposit_events.key().to_vec()), - ])), - ])) - } - - /// Returns the value layout for the account's CoinStore - pub fn layout() -> MoveStructLayout { - MoveStructLayout::new(vec![ - MoveTypeLayout::U64, - MoveTypeLayout::Struct(MoveStructLayout::new(vec![ - MoveTypeLayout::U64, - MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), - ])), - MoveTypeLayout::Struct(MoveStructLayout::new(vec![ - MoveTypeLayout::U64, - MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), - ])), - ]) - } -} +// +// //--------------------------------------------------------------------------- +// // CoinStore resource represenation +// //--------------------------------------------------------------------------- +// +// /// Struct that represents an account CoinStore resource for tests. +// #[derive(Clone, Debug, Eq, PartialEq)] +// pub struct CoinStore { +// coin: u64, +// deposit_events: EventHandle, +// withdraw_events: EventHandle, +// } +// +// impl CoinStore { +// /// Create a new CoinStore +// pub fn new(coin: u64, deposit_events: EventHandle, withdraw_events: EventHandle) -> Self { +// Self { +// coin, +// deposit_events, +// withdraw_events, +// } +// } +// +// /// Retrieve the balance inside of this +// pub fn coin(&self) -> u64 { +// self.coin +// } +// +// /// Returns the Move Value for the account's CoinStore +// pub fn to_value(&self) -> Value { +// Value::struct_(Struct::pack(vec![ +// Value::u64(self.coin), +// Value::struct_(Struct::pack(vec![ +// Value::u64(self.withdraw_events.count()), +// Value::vector_u8(self.withdraw_events.key().to_vec()), +// ])), +// Value::struct_(Struct::pack(vec![ +// Value::u64(self.deposit_events.count()), +// Value::vector_u8(self.deposit_events.key().to_vec()), +// ])), +// ])) +// } +// +// /// Returns the value layout for the account's CoinStore +// pub fn layout() -> MoveStructLayout { +// MoveStructLayout::new(vec![ +// MoveTypeLayout::U64, +// MoveTypeLayout::Struct(MoveStructLayout::new(vec![ +// MoveTypeLayout::U64, +// MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), +// ])), +// MoveTypeLayout::Struct(MoveStructLayout::new(vec![ +// MoveTypeLayout::U64, +// MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), +// ])), +// ]) +// } +// } //--------------------------------------------------------------------------- // Account type represenation @@ -372,7 +430,7 @@ impl CoinStore { #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum AccountRoleSpecifier { - AptosRoot, + Root, TreasuryCompliance, DesignatedDealer, Validator, @@ -384,7 +442,7 @@ pub enum AccountRoleSpecifier { impl AccountRoleSpecifier { pub fn id(&self) -> u64 { match self { - Self::AptosRoot => 0, + Self::Root => 0, Self::TreasuryCompliance => 1, Self::DesignatedDealer => 2, Self::Validator => 3, @@ -455,13 +513,22 @@ impl AccountRole { /// `AccountData` captures the initial state needed to create accounts for tests. #[derive(Clone, Debug, Eq, PartialEq)] pub struct AccountData { + // account: Account, + // withdrawal_capability: Option, + // key_rotation_capability: Option, + // sequence_number: u64, + // + // coin_store: CoinStore, + // account_role: AccountRole, account: Account, - withdrawal_capability: Option, - key_rotation_capability: Option, sequence_number: u64, - - coin_store: CoinStore, - account_role: AccountRole, + key_rotation_capability: Option, + withdrawal_capability: Option, + withdraw_events: EventHandle, + deposit_events: EventHandle, + accept_token_events: EventHandle, + balances: BTreeMap, + event_generator: EventHandleGenerator, } fn new_event_handle(count: u64, address: AccountAddress) -> EventHandle { @@ -472,7 +539,7 @@ impl AccountData { /// Creates a new `AccountData` with a new account. /// /// This constructor is non-deterministic and should not be used against golden file. - pub fn new(balance: u64, sequence_number: u64) -> Self { + pub fn new(balance: u128, sequence_number: u64) -> Self { Self::with_account( Account::new(), balance, @@ -484,7 +551,7 @@ impl AccountData { /// Creates a new `AccountData` with a new account. /// /// Most tests will want to use this constructor. - pub fn new_from_seed(seed: &mut KeyGen, balance: u64, sequence_number: u64) -> Self { + pub fn new_from_seed(seed: &mut KeyGen, balance: u128, sequence_number: u64) -> Self { Self::with_account( Account::new_from_seed(seed), balance, @@ -496,7 +563,7 @@ impl AccountData { /// Creates a new `AccountData` with the provided account. pub fn with_account( account: Account, - balance: u64, + balance: u128, sequence_number: u64, account_specifier: AccountRoleSpecifier, ) -> Self { @@ -514,7 +581,7 @@ impl AccountData { pub fn with_keypair( privkey: Ed25519PrivateKey, pubkey: Ed25519PublicKey, - balance: u64, + balance: u128, sequence_number: u64, account_specifier: AccountRoleSpecifier, ) -> Self { @@ -525,24 +592,25 @@ impl AccountData { /// Creates a new `AccountData` with custom parameters. pub fn with_account_and_event_counts( account: Account, - balance: u64, + balance: u128, sequence_number: u64, sent_events_count: u64, received_events_count: u64, - account_specifier: AccountRoleSpecifier, + _account_specifier: AccountRoleSpecifier, ) -> Self { let addr = *account.address(); + let mut balances_map = BTreeMap::new(); + balances_map.insert(STC_TOKEN_CODE_STR.to_string(), Balance::new(balance)); Self { - account_role: AccountRole::new(*account.address(), account_specifier), - withdrawal_capability: Some(WithdrawCapability::new(addr)), - key_rotation_capability: Some(KeyRotationCapability::new(addr)), + event_generator: EventHandleGenerator::new_with_event_count(addr, 3), account, - coin_store: CoinStore::new( - balance, - new_event_handle(received_events_count, addr), - new_event_handle(sent_events_count, addr), - ), + balances: balances_map, sequence_number, + key_rotation_capability: None, + withdrawal_capability: Some(WithdrawCapability::new(addr)), + withdraw_events: EventHandle::new_from_address(&addr, sent_events_count), + deposit_events: EventHandle::new_from_address(&addr, received_events_count), + accept_token_events: EventHandle::new_from_address(&addr, 0), } } @@ -551,29 +619,87 @@ impl AccountData { self.account.rotate_key(privkey, pubkey) } + pub fn sent_payment_event_layout() -> MoveStructLayout { + MoveStructLayout::new(vec![ + MoveTypeLayout::U128, + MoveTypeLayout::Address, + MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), + ]) + } + + pub fn received_payment_event_type() -> MoveStructLayout { + MoveStructLayout::new(vec![ + MoveTypeLayout::U128, + MoveTypeLayout::Address, + MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), + ]) + } + + pub fn event_handle_layout() -> MoveStructLayout { + MoveStructLayout::new(vec![ + MoveTypeLayout::U64, + MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), + ]) + } + /// Returns the (Move value) layout of the Account::Account struct pub fn layout() -> MoveStructLayout { use MoveStructLayout as S; use MoveTypeLayout as T; - S::new(vec![T::Vector(Box::new(T::U8)), T::U64, T::Address]) + S::new(vec![ + T::Vector(Box::new(T::U8)), + T::Vector(Box::new(T::Struct(WithdrawCapability::layout()))), + T::Vector(Box::new(T::Struct(KeyRotationCapability::layout()))), + T::Struct(Self::event_handle_layout()), + T::Struct(Self::event_handle_layout()), + T::Struct(Self::event_handle_layout()), + T::U64, + ]) } /// Returns the account role specifier pub fn account_role(&self) -> AccountRoleSpecifier { - self.account_role.account_specifier() + //self.account_role.account_specifier() + AccountRoleSpecifier::ParentVASP } /// Creates and returns the top-level resources to be published under the account - pub fn to_value(&self) -> (Value, Value) { + pub fn to_value(&self) -> (Value, Vec<(String, Value)>, Value) { // TODO: publish some concept of Account + let balances: Vec<_> = self + .balances + .iter() + .map(|(code, balance)| (code.clone(), balance.to_value())) + .collect(); + let event_generator = self.event_generator.to_value(); let account = Value::struct_(Struct::pack(vec![ // TODO: this needs to compute the auth key instead - Value::vector_u8(AuthenticationKey::ed25519(&self.account.pubkey).to_vec()), + Value::vector_u8(self.account.auth_key().to_vec()), + self.withdrawal_capability + .as_ref() + .map(|v| v.value()) + .unwrap_or_else(|| Value::vector_for_testing_only(vec![])), + self.key_rotation_capability + .as_ref() + .map(|v| v.value()) + .unwrap_or_else(|| Value::vector_for_testing_only(vec![])), + + Value::struct_(Struct::pack(vec![ + Value::u64(self.withdraw_events.count()), + Value::vector_u8(self.withdraw_events.key().to_vec()), + ])), + Value::struct_(Struct::pack(vec![ + Value::u64(self.deposit_events.count()), + Value::vector_u8(self.deposit_events.key().to_vec()), + ])), + Value::struct_(Struct::pack(vec![ + Value::u64(self.accept_token_events.count()), + Value::vector_u8(self.accept_token_events.key().to_vec()), + ])), Value::u64(self.sequence_number), - Value::address(*self.address()), ])); - (account, self.coin_store.to_value()) + (account, balances, event_generator) } /// Returns the AccessPath that describes the Account resource instance. @@ -583,11 +709,15 @@ impl AccountData { self.account.make_account_access_path() } - /// Returns the AccessPath that describes the Account's CoinStore resource instance. + /// Returns the AccessPath that describes the Account's Balance resource instance. /// - /// Use this to retrieve or publish the Account's CoinStore blob. - pub fn make_coin_store_access_path(&self) -> AccessPath { - self.account.make_coin_store_access_path() + /// Use this to retrieve or publish the Account's Balance blob. + pub fn make_balance_access_path(&self, token_code: &str) -> AccessPath { + self.account.make_balance_access_path(token_code) + } + + pub fn make_event_generator_access_path(&self) -> AccessPath { + self.account.make_event_generator_access_path() } pub fn transfer_event_layout() -> MoveStructLayout { @@ -601,7 +731,7 @@ impl AccountData { /// Creates a writeset that contains the account data and can be patched to the storage /// directly. pub fn to_writeset(&self) -> WriteSet { - let (account_blob, coinstore_blob) = self.to_value(); + let (account_blob, balance_blobs, event_generator_blob) = self.to_value(); let mut write_set = Vec::new(); let account = account_blob .value_as::() @@ -612,17 +742,27 @@ impl AccountData { StateKey::AccessPath(self.make_account_access_path()), WriteOp::Value(account), )); + for (code, balance_blob) in balance_blobs.into_iter() { + let balance = balance_blob + .value_as::() + .unwrap() + .simple_serialize(&Balance::layout()) + .unwrap(); + write_set.push(( + StateKey::AccessPath(self.make_balance_access_path(code.as_str())), + WriteOp::Value(balance), + )); + } - let balance = coinstore_blob + let event_generator = event_generator_blob .value_as::() .unwrap() - .simple_serialize(&CoinStore::layout()) + .simple_serialize(&EventHandleGenerator::layout()) .unwrap(); write_set.push(( - StateKey::AccessPath(self.make_coin_store_access_path()), - WriteOp::Value(balance), + StateKey::AccessPath(self.make_event_generator_access_path()), + WriteOp::Value(event_generator), )); - WriteSetMut::new(write_set).freeze().unwrap() } @@ -645,8 +785,11 @@ impl AccountData { } /// Returns the initial balance. - pub fn balance(&self) -> u64 { - self.coin_store.coin() + pub fn balance(&self) -> u128 { + self.balances + .get(STC_TOKEN_CODE_STR) + .expect("get balance by currency_code fail") + .token() } /// Returns the initial sequence number. @@ -656,22 +799,22 @@ impl AccountData { /// Returns the unique key for this sent events stream. pub fn sent_events_key(&self) -> &[u8] { - self.coin_store.withdraw_events.key().as_bytes() + self.withdraw_events.key().as_bytes() } /// Returns the initial sent events count. pub fn sent_events_count(&self) -> u64 { - self.coin_store.withdraw_events.count() + self.withdraw_events.count() } /// Returns the unique key for this received events stream. pub fn received_events_key(&self) -> &[u8] { - self.coin_store.deposit_events.key().as_bytes() + self.deposit_events.key().as_bytes() } /// Returns the initial received events count. pub fn received_events_count(&self) -> u64 { - self.coin_store.deposit_events.count() + self.deposit_events.count() } } @@ -679,6 +822,7 @@ impl AccountData { pub struct WithdrawCapability { account_address: AccountAddress, } + impl WithdrawCapability { pub fn new(account_address: AccountAddress) -> Self { Self { account_address } @@ -699,6 +843,7 @@ impl WithdrawCapability { pub struct KeyRotationCapability { account_address: AccountAddress, } + impl KeyRotationCapability { pub fn new(account_address: AccountAddress) -> Self { Self { account_address } diff --git a/vm/e2e-tests/src/account_universe.rs b/vm/e2e-tests/src/account_universe.rs index 9cd85969b7..e3fec93e44 100644 --- a/vm/e2e-tests/src/account_universe.rs +++ b/vm/e2e-tests/src/account_universe.rs @@ -137,7 +137,7 @@ impl AccountCurrent { let received_events_count = initial_data.received_events_count(); Self { initial_data, - balance, + balance: balance as u64, sequence_number, sent_events_count, received_events_count, diff --git a/vm/e2e-tests/src/account_universe/create_account.rs b/vm/e2e-tests/src/account_universe/create_account.rs index e9b74de2e1..f85c1889a3 100644 --- a/vm/e2e-tests/src/account_universe/create_account.rs +++ b/vm/e2e-tests/src/account_universe/create_account.rs @@ -55,7 +55,7 @@ impl AUTransactionGen for CreateAccountGen { sender.event_counter_created = true; universe.add_account(AccountData::with_account( self.new_account.clone(), - self.amount, + self.amount as u128, 0, AccountRoleSpecifier::default(), )); diff --git a/vm/e2e-tests/src/account_universe/peer_to_peer.rs b/vm/e2e-tests/src/account_universe/peer_to_peer.rs index 61e58ea6ab..3bb47aa824 100644 --- a/vm/e2e-tests/src/account_universe/peer_to_peer.rs +++ b/vm/e2e-tests/src/account_universe/peer_to_peer.rs @@ -111,6 +111,7 @@ impl AUTransactionGen for P2PTransferGen { ); } } + println!("AUTransactionGen::apply | Exited: {:?}", status); (txn, (status, gas_used)) } } diff --git a/vm/e2e-tests/src/common_transactions.rs b/vm/e2e-tests/src/common_transactions.rs index 5f2379150d..7f8b0c57e9 100644 --- a/vm/e2e-tests/src/common_transactions.rs +++ b/vm/e2e-tests/src/common_transactions.rs @@ -40,7 +40,7 @@ pub fn empty_txn( ) -> SignedUserTransaction { build_signed_empty_txn( sender.address().clone(), - &sender.privkey.clone().into(), + &sender.private_key(), seq_num, now_time() + DEFAULT_EXPIRATION_TIME, ChainId::test(), @@ -60,11 +60,9 @@ pub fn create_account_txn( new_account: &Account, seq_num: u64, ) -> SignedUserTransaction { - let starcoin_acc = StarcoinAccount::with_keypair( - new_account.privkey.clone().into(), - new_account.pubkey.clone().into(), - Some(new_account.address().clone()), - ); + let (pub_k, priv_k) = new_account.account_keypair(); + let starcoin_acc = + StarcoinAccount::with_keypair(priv_k, pub_k, Some(new_account.address().clone())); create_account_txn_sent_as_association( &starcoin_acc, seq_num + 1, @@ -98,11 +96,8 @@ pub fn peer_to_peer_txn( // )) // .sequence_number(seq_num) // .sign() - let starcoin_acc = StarcoinAccount::with_keypair( - sender.privkey.clone().into(), - sender.pubkey.clone().into(), - Some(sender.address().clone()), - ); + let (pub_k, priv_k) = sender.account_keypair(); + let starcoin_acc = StarcoinAccount::with_keypair(priv_k, pub_k, Some(sender.address().clone())); peer_to_peer_v2( &starcoin_acc, receiver.address(), diff --git a/vm/e2e-tests/src/data_store.rs b/vm/e2e-tests/src/data_store.rs index bf9c595b7f..d2bf7d44bb 100644 --- a/vm/e2e-tests/src/data_store.rs +++ b/vm/e2e-tests/src/data_store.rs @@ -1,7 +1,7 @@ // Copyright (c) Starcoin // SPDX-License-Identifier: Apache-2.0 -//! Support for mocking the Aptos data store. +//! Support for mocking the Starcoin data store. use crate::account::AccountData; use anyhow::Result; use serde::{Deserialize, Serialize}; @@ -46,6 +46,8 @@ impl FakeDataStore { /// Adds a [`WriteSet`] to this data store. pub fn add_write_set(&self, write_set: &WriteSet) { + println!("FakeDataStore::add_write_set | {:#?}", write_set); + let mut write_handle = self.state_data.write().expect("Panic for lock"); for (state_key, write_op) in write_set { match write_op { @@ -99,6 +101,8 @@ impl FakeDataStore { // TODO: only the "sync" get is implemented impl StateView for FakeDataStore { fn get_state_value(&self, state_key: &StateKey) -> Result>> { + println!("StateView::get_state_value, state_key: {:#?}", state_key); + Ok(self.inner().get(state_key).cloned()) } diff --git a/vm/e2e-tests/src/executor.rs b/vm/e2e-tests/src/executor.rs index ded53c6f4f..49681c0017 100644 --- a/vm/e2e-tests/src/executor.rs +++ b/vm/e2e-tests/src/executor.rs @@ -14,9 +14,9 @@ use starcoin_crypto::keygen::KeyGen; use starcoin_crypto::HashValue; use starcoin_gas::{StarcoinGasMeter, StarcoinGasParameters}; use starcoin_gas_algebra_ext::InitialGasSchedule; -use starcoin_vm_runtime::block_executor::BlockStarcoinVM; use starcoin_vm_runtime::data_cache::{AsMoveResolver, RemoteStorage}; use starcoin_vm_runtime::move_vm_ext::{MoveVmExt, SessionId, SessionOutput}; +use starcoin_vm_runtime::parallel_executor::ParallelStarcoinVM; use starcoin_vm_runtime::starcoin_vm::StarcoinVM; use starcoin_vm_runtime::VMExecutor; use starcoin_vm_types::{ @@ -64,7 +64,7 @@ pub type TraceSeqMapping = (usize, Vec, Vec); /// Provides an environment to run a VM instance. /// -/// This struct is a mock in-memory implementation of the Aptos executor. +/// This struct is a mock in-memory implementation of the Starcoin executor. #[derive(Debug)] pub struct FakeExecutor { data_store: FakeDataStore, @@ -227,7 +227,7 @@ impl FakeExecutor { } /// Create one instance of [`AccountData`] without saving it to data store. - pub fn create_raw_account_data(&mut self, balance: u64, seq_num: u64) -> AccountData { + pub fn create_raw_account_data(&mut self, balance: u128, seq_num: u64) -> AccountData { AccountData::new_from_seed(&mut self.rng, balance, seq_num) } @@ -236,7 +236,7 @@ impl FakeExecutor { pub fn create_accounts(&mut self, size: usize, balance: u64, seq_num: u64) -> Vec { let mut accounts: Vec = Vec::with_capacity(size); for _i in 0..size { - let account_data = AccountData::new_from_seed(&mut self.rng, balance, seq_num); + let account_data = AccountData::new_from_seed(&mut self.rng, balance as u128, seq_num); self.add_account_data(&account_data); accounts.push(account_data.into_account()); } @@ -364,7 +364,7 @@ impl FakeExecutor { &self, txn_block: Vec, ) -> Result, VMStatus> { - let (result, _) = BlockStarcoinVM::execute_block( + let (result, _) = ParallelStarcoinVM::execute_block( txn_block, &self.data_store, num_cpus::get(), @@ -481,7 +481,9 @@ impl FakeExecutor { HashValue::zero(), self.block_time, minter_account.address().clone(), - Some(AuthenticationKey::ed25519(&minter_account.account().pubkey)), + Some(AuthenticationKey::ed25519( + &minter_account.account().public_key(), + )), 0, 0, ChainId::test(), diff --git a/vm/e2e-tests/src/gas_costs.rs b/vm/e2e-tests/src/gas_costs.rs index d505129b0f..c491ca2973 100644 --- a/vm/e2e-tests/src/gas_costs.rs +++ b/vm/e2e-tests/src/gas_costs.rs @@ -60,7 +60,7 @@ pub static CREATE_ACCOUNT_TOO_LOW_FIRST: Lazy = Lazy::new(|| { // The gas amount is the minimum that needs to be reserved, so use a value that's // clearly higher than that. let balance = TXN_RESERVED + 10_000; - let sender = AccountData::new(balance, 10); + let sender = AccountData::new(balance as u128, 10); executor.add_account_data(&sender); let receiver = Account::new(); @@ -77,7 +77,7 @@ pub static CREATE_ACCOUNT_TOO_LOW_NEXT: Lazy = Lazy::new(|| { // The gas amount is the minimum that needs to be reserved, so use a value that's // clearly higher than that. let balance = (2 * TXN_RESERVED) + 10_000; - let sender = AccountData::new(balance, 10); + let sender = AccountData::new(balance as u128, 10); executor.add_account_data(&sender); let txns = vec![ @@ -150,7 +150,7 @@ pub static PEER_TO_PEER_TOO_LOW: Lazy = Lazy::new(|| { // The gas amount is the minimum that needs to be reserved, so use a value that's clearly // higher than that. let balance = TXN_RESERVED + 10_000; - let sender = AccountData::new(balance, 10); + let sender = AccountData::new(balance as u128, 10); let receiver = AccountData::new(1_000_000, 10); executor.add_account_data(&sender); executor.add_account_data(&receiver); @@ -206,7 +206,7 @@ pub static PEER_TO_PEER_NEW_RECEIVER_TOO_LOW_FIRST: Lazy = Lazy::new(|| { // The gas amount is the minimum that needs to be reserved, so use a value that's // clearly higher than that. let balance = TXN_RESERVED + 10_000; - let sender = AccountData::new(balance, 10); + let sender = AccountData::new(balance as u128, 10); executor.add_account_data(&sender); let receiver = Account::new(); @@ -224,7 +224,7 @@ pub static PEER_TO_PEER_NEW_RECEIVER_TOO_LOW_NEXT: Lazy = Lazy::new(|| { // The gas amount is the minimum that needs to be reserved, so use a value that's // clearly higher than that. let balance = (2 * TXN_RESERVED) + 20_000; - let sender = AccountData::new(balance, 10); + let sender = AccountData::new(balance as u128, 10); executor.add_account_data(&sender); let txns = vec![ diff --git a/vm/e2e-tests/src/proptest_types.rs b/vm/e2e-tests/src/proptest_types.rs index e26d46946f..4a38faa1f5 100644 --- a/vm/e2e-tests/src/proptest_types.rs +++ b/vm/e2e-tests/src/proptest_types.rs @@ -35,7 +35,7 @@ impl AccountData { |(account, balance, sequence_number, sent_events_count, received_events_count)| { AccountData::with_account_and_event_counts( account, - balance, + balance as u128, sequence_number, sent_events_count, received_events_count, diff --git a/vm/transaction-benchmarks/src/transactions.rs b/vm/transaction-benchmarks/src/transactions.rs index 34da56e928..bb90172508 100644 --- a/vm/transaction-benchmarks/src/transactions.rs +++ b/vm/transaction-benchmarks/src/transactions.rs @@ -252,7 +252,7 @@ impl TransactionBenchState { HashValue::zero(), 0, minter_account.address().clone(), - Some(AuthenticationKey::ed25519(&minter_account.account().pubkey)), + Some(AuthenticationKey::ed25519(&minter_account.account().public_key())), 0, 0, ChainId::test(), diff --git a/vm/vm-runtime/src/block_executor/mod.rs b/vm/vm-runtime/src/block_executor/mod.rs index c2ccf4d2c1..861fa7bc77 100644 --- a/vm/vm-runtime/src/block_executor/mod.rs +++ b/vm/vm-runtime/src/block_executor/mod.rs @@ -228,7 +228,7 @@ impl BlockStarcoinVM { println!("Sequential execution starts..."); let seq_timer = Instant::now(); let mut vm = StarcoinVM::new(None); - let ret = vm.execute_block_transactions(state_view, transactions, None); + let _ret = vm.execute_block_transactions(state_view, transactions, None); let seq_exec_t = seq_timer.elapsed(); println!( "Sequential execution finishes, TPS = {}", From 863cae9d9183c48a14a653808797c7912b2e5f57 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Thu, 28 Sep 2023 21:07:34 +0800 Subject: [PATCH 42/89] fix some block meta creation error --- Cargo.lock | 1 + vm/e2e-tests/Cargo.toml | 1 + vm/e2e-tests/src/account.rs | 5 +-- vm/e2e-tests/src/account_universe.rs | 2 +- .../src/account_universe/peer_to_peer.rs | 2 +- vm/e2e-tests/src/common_transactions.rs | 2 + vm/e2e-tests/src/executor.rs | 15 +++---- vm/transaction-benchmarks/src/main.rs | 37 +++++++++++++----- vm/transaction-benchmarks/src/transactions.rs | 39 ++++++++++++------- vm/transaction-builder/src/lib.rs | 3 +- vm/vm-runtime/src/errors.rs | 1 + 11 files changed, 70 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3fac300827..3df460d0c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9854,6 +9854,7 @@ dependencies = [ "starcoin-proptest-helpers", "starcoin-state-tree", "starcoin-statedb", + "starcoin-time-service", "starcoin-transaction-builder", "starcoin-types", "starcoin-vm-runtime", diff --git a/vm/e2e-tests/Cargo.toml b/vm/e2e-tests/Cargo.toml index 51eaaa7a56..7fa9903701 100644 --- a/vm/e2e-tests/Cargo.toml +++ b/vm/e2e-tests/Cargo.toml @@ -38,4 +38,5 @@ starcoin-gas = { workspace = true } move-table-extension = { workspace = true } starcoin-statedb = { workspace = true } starcoin-state-tree = { workspace = true } +starcoin-time-service = { workspace = true } diff --git a/vm/e2e-tests/src/account.rs b/vm/e2e-tests/src/account.rs index e79a25d251..5b4bbec6ac 100644 --- a/vm/e2e-tests/src/account.rs +++ b/vm/e2e-tests/src/account.rs @@ -19,9 +19,7 @@ use starcoin_vm_types::language_storage::StructTag; use starcoin_vm_types::move_resource::MoveResource; use starcoin_vm_types::state_store::state_key::StateKey; use starcoin_vm_types::token::token_code::TokenCode; -use starcoin_vm_types::transaction::authenticator::{ - AccountPrivateKey, AccountPublicKey -}; +use starcoin_vm_types::transaction::authenticator::{AccountPrivateKey, AccountPublicKey}; use starcoin_vm_types::transaction::{ RawUserTransaction, Script, ScriptFunction, SignedUserTransaction, TransactionPayload, }; @@ -684,7 +682,6 @@ impl AccountData { .as_ref() .map(|v| v.value()) .unwrap_or_else(|| Value::vector_for_testing_only(vec![])), - Value::struct_(Struct::pack(vec![ Value::u64(self.withdraw_events.count()), Value::vector_u8(self.withdraw_events.key().to_vec()), diff --git a/vm/e2e-tests/src/account_universe.rs b/vm/e2e-tests/src/account_universe.rs index e3fec93e44..a66aed1b64 100644 --- a/vm/e2e-tests/src/account_universe.rs +++ b/vm/e2e-tests/src/account_universe.rs @@ -410,7 +410,7 @@ pub fn assert_accounts_match( .read_account_resource(account.account()) .expect("account resource must exist"); let coin_store_resource = executor - .read_coin_store_resource(account.account()) + .read_balance_resource(account.account()) .expect("account balance resource must exist"); let auth_key = account.account().auth_key(); prop_assert_eq!( diff --git a/vm/e2e-tests/src/account_universe/peer_to_peer.rs b/vm/e2e-tests/src/account_universe/peer_to_peer.rs index 3bb47aa824..6c92ddcc65 100644 --- a/vm/e2e-tests/src/account_universe/peer_to_peer.rs +++ b/vm/e2e-tests/src/account_universe/peer_to_peer.rs @@ -111,7 +111,7 @@ impl AUTransactionGen for P2PTransferGen { ); } } - println!("AUTransactionGen::apply | Exited: {:?}", status); + // println!("AUTransactionGen::apply | Exited: {:?}", status); (txn, (status, gas_used)) } } diff --git a/vm/e2e-tests/src/common_transactions.rs b/vm/e2e-tests/src/common_transactions.rs index 7f8b0c57e9..d1bd529904 100644 --- a/vm/e2e-tests/src/common_transactions.rs +++ b/vm/e2e-tests/src/common_transactions.rs @@ -5,6 +5,7 @@ use crate::account::Account; use starcoin_config::ChainNetwork; +pub use starcoin_time_service::duration_since_epoch; use starcoin_transaction_builder::{build_signed_empty_txn, peer_to_peer_v2}; use starcoin_types::account::Account as StarcoinAccount; use starcoin_types::account::DEFAULT_EXPIRATION_TIME; @@ -102,6 +103,7 @@ pub fn peer_to_peer_txn( &starcoin_acc, receiver.address(), seq_num, + duration_since_epoch().as_secs() + 100, transfer_amount as u128, &ChainNetwork::new_test(), ) diff --git a/vm/e2e-tests/src/executor.rs b/vm/e2e-tests/src/executor.rs index 49681c0017..f4e07db1ea 100644 --- a/vm/e2e-tests/src/executor.rs +++ b/vm/e2e-tests/src/executor.rs @@ -14,9 +14,9 @@ use starcoin_crypto::keygen::KeyGen; use starcoin_crypto::HashValue; use starcoin_gas::{StarcoinGasMeter, StarcoinGasParameters}; use starcoin_gas_algebra_ext::InitialGasSchedule; +use starcoin_vm_runtime::block_executor::BlockStarcoinVM; use starcoin_vm_runtime::data_cache::{AsMoveResolver, RemoteStorage}; use starcoin_vm_runtime::move_vm_ext::{MoveVmExt, SessionId, SessionOutput}; -use starcoin_vm_runtime::parallel_executor::ParallelStarcoinVM; use starcoin_vm_runtime::starcoin_vm::StarcoinVM; use starcoin_vm_runtime::VMExecutor; use starcoin_vm_types::{ @@ -118,8 +118,9 @@ impl FakeExecutor { let fake_executor = Self::no_genesis(); let net = ChainNetwork::new_test(); let genesis_txn = Genesis::build_genesis_transaction(&net).unwrap(); - let _txn_info = + let useless = Genesis::execute_genesis_txn(fake_executor.get_state_view(), genesis_txn).unwrap(); + drop(useless); fake_executor } @@ -292,13 +293,13 @@ impl FakeExecutor { } /// Reads the CoinStore resource value for an account from this executor's data store. - pub fn read_coin_store_resource(&self, account: &Account) -> Option { - self.read_coin_store_resource_at_address(account.address()) + pub fn read_balance_resource(&self, account: &Account) -> Option { + self.read_balance_resource_at_address(account.address()) } - /// Reads the CoinStore resource value for an account under the given address from this executor's + /// Reads the balance resource value for an account under the given address from this executor's /// data store. - pub fn read_coin_store_resource_at_address( + pub fn read_balance_resource_at_address( &self, addr: &AccountAddress, ) -> Option { @@ -364,7 +365,7 @@ impl FakeExecutor { &self, txn_block: Vec, ) -> Result, VMStatus> { - let (result, _) = ParallelStarcoinVM::execute_block( + let (result, _) = BlockStarcoinVM::execute_block( txn_block, &self.data_store, num_cpus::get(), diff --git a/vm/transaction-benchmarks/src/main.rs b/vm/transaction-benchmarks/src/main.rs index 7ef1fa716c..c185b1feb6 100644 --- a/vm/transaction-benchmarks/src/main.rs +++ b/vm/transaction-benchmarks/src/main.rs @@ -37,9 +37,18 @@ fn main() { let mut run_par = opt.run_par; let run_seq = true; - assert!(!concurrency_levels.is_empty(), "Concurrcy level array is empty!"); - assert!(!txns.is_empty(), "Transaction numbers level array is empty!"); - assert!(!account_nums.is_empty(), "Transaction numbers level array is empty!"); + assert!( + !concurrency_levels.is_empty(), + "Concurrcy level array is empty!" + ); + assert!( + !txns.is_empty(), + "Transaction numbers level array is empty!" + ); + assert!( + !account_nums.is_empty(), + "Transaction numbers level array is empty!" + ); // if !concurrency_levels.is_empty() { // run_par = true; @@ -51,19 +60,26 @@ fn main() { default_num_transactions, ); - // let acts = [1000]; //let txns = [10000, 50000, 100000]; let num_warmups = 2; let num_runs = 10; - println!("num cpus = {}, run_seq: {}, run_seq: {}", num_cpus::get(), run_seq, run_seq); + println!( + "num cpus = {}, run_seq: {}, run_seq: {}", + num_cpus::get(), + run_seq, + run_seq + ); for concurrency_level in &concurrency_levels { let mut par_measurements = Vec::new(); let mut seq_measurements = Vec::new(); - println!("=========== concurrency_level: {} started ===========", concurrency_level); + println!( + "=========== concurrency_level: {} started ===========", + concurrency_level + ); for num_accounts in &account_nums { println!("=== accounts_num: {} started ===", num_accounts); @@ -103,7 +119,7 @@ fn main() { seq_sum += m; } seq_tps = seq_sum / seq_measurement.len(); - println!("Avg Sequential TPS = {:?}", seq_tps, ); + println!("Avg Sequential TPS = {:?}", seq_tps,); } if run_par { @@ -113,7 +129,7 @@ fn main() { par_sum += m; } let par_tps = par_sum / par_measurement.len(); - println!("Avg Parallel TPS = {:?}", par_tps, ); + println!("Avg Parallel TPS = {:?}", par_tps,); if run_seq { println!("Speed up {}x over sequential", par_tps / seq_tps); } @@ -121,6 +137,9 @@ fn main() { i += 1; } } - println!("=========== concurrency_level: {} finished ===========", concurrency_level); + println!( + "=========== concurrency_level: {} finished ===========", + concurrency_level + ); } } diff --git a/vm/transaction-benchmarks/src/transactions.rs b/vm/transaction-benchmarks/src/transactions.rs index bb90172508..e53a862858 100644 --- a/vm/transaction-benchmarks/src/transactions.rs +++ b/vm/transaction-benchmarks/src/transactions.rs @@ -16,10 +16,11 @@ use starcoin_language_e2e_tests::{ executor::FakeExecutor, gas_costs::TXN_RESERVED, }; +use starcoin_language_e2e_tests::common_transactions::duration_since_epoch; use starcoin_types::{block_metadata::BlockMetadata, transaction::Transaction}; -use starcoin_vm_runtime::{block_executor::BlockStarcoinVM, starcoin_vm::StarcoinVM, VMExecutor}; +use starcoin_vm_runtime::{block_executor::BlockStarcoinVM, starcoin_vm::StarcoinVM}; use starcoin_vm_types::genesis_config::ChainId; use starcoin_vm_types::transaction::authenticator::AuthenticationKey; @@ -126,9 +127,7 @@ where "RUN benchmark for: num_threads = {}, \ num_account = {}, \ block_size = {}", - concurrency_level, - num_accounts, - num_txn, + concurrency_level, num_accounts, num_txn, ); let tps = state.execute_blockstm_benchmark(concurrency_level, run_par, run_seq); par_tps.push(tps.0); @@ -247,14 +246,20 @@ impl TransactionBenchState { // vec![], // 1, // ); - let minter_account = AccountData::new(10000, 0); + // XXX FIXME YSG + // let minter_account = AccountData::new(10000, 0); + let minter_account = AccountData::new(10_000_000_000, 0); + state.executor.add_account_data(&minter_account); + let timestamp = duration_since_epoch().as_millis() as u64; let new_block = BlockMetadata::new( HashValue::zero(), - 0, + timestamp, minter_account.address().clone(), - Some(AuthenticationKey::ed25519(&minter_account.account().public_key())), - 0, + Some(AuthenticationKey::ed25519( + &minter_account.account().public_key(), + )), 0, + 1, ChainId::test(), 0, ); @@ -313,13 +318,17 @@ impl TransactionBenchState { // this bench execution with TPS let timer = Instant::now(); - let useless = StarcoinVM::execute_block( - self.transactions, - self.executor.get_state_view(), - None, - None, - ) - .expect("VM should not fail to start"); + let useless = self + .executor + .execute_transaction_block(self.transactions) + .expect("VM should not fail to start"); + // let useless = StarcoinVM::execute_block( + // self.transactions, + // self.executor.get_state_view(), + // None, + // None, + // ) + // .expect("VM should not fail to start"); drop(useless); diff --git a/vm/transaction-builder/src/lib.rs b/vm/transaction-builder/src/lib.rs index 0019c4512b..456b5a1387 100644 --- a/vm/transaction-builder/src/lib.rs +++ b/vm/transaction-builder/src/lib.rs @@ -299,6 +299,7 @@ pub fn peer_to_peer_v2( sender: &Account, recipient: &AccountAddress, seq_num: u64, + expiration_timestamp_secs: u64, amount: u128, net: &ChainNetwork, ) -> SignedUserTransaction { @@ -319,7 +320,7 @@ pub fn peer_to_peer_v2( )), 10000000, 1, - 1000 + 60 * 60, + expiration_timestamp_secs, net.chain_id(), )) } diff --git a/vm/vm-runtime/src/errors.rs b/vm/vm-runtime/src/errors.rs index 70e7668f4b..442c43ff1e 100644 --- a/vm/vm-runtime/src/errors.rs +++ b/vm/vm-runtime/src/errors.rs @@ -43,6 +43,7 @@ pub fn error_split(code: u64) -> (u8, u64) { } pub fn convert_prologue_runtime_error(error: VMError) -> Result<(), VMStatus> { + println!("convert_prologue_runtime_error VMError: {:#?}", error); let status = error.into_vm_status(); Err(match status { VMStatus::Executed => VMStatus::Executed, From 64d34a406f04e45e0dbdec9c32d65fbc011b0c91 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Thu, 28 Sep 2023 21:29:15 +0800 Subject: [PATCH 43/89] add unittest for transaction --- executor/tests/error_code_test.rs | 80 +++++++++++++++++++ vm/transaction-benchmarks/src/transactions.rs | 2 +- 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/executor/tests/error_code_test.rs b/executor/tests/error_code_test.rs index cef86b1cd3..95f6e5a909 100644 --- a/executor/tests/error_code_test.rs +++ b/executor/tests/error_code_test.rs @@ -4,6 +4,7 @@ use anyhow::Result; use once_cell::sync::Lazy; use starcoin_crypto::hash::PlainCryptoHash; +use starcoin_state_api::ChainStateWriter; use starcoin_transaction_builder::{ encode_transfer_script_by_token_code, DEFAULT_EXPIRATION_TIME, DEFAULT_MAX_GAS_AMOUNT, }; @@ -14,6 +15,7 @@ use starcoin_types::{ account::Account, block_metadata::BlockMetadata, transaction::Transaction, transaction::TransactionStatus, }; +use starcoin_vm_runtime::starcoin_vm::StarcoinVM; use starcoin_vm_types::account_address::AccountAddress; use starcoin_vm_types::account_config::core_code_address; use starcoin_vm_types::account_config::{genesis_address, stc_type_tag}; @@ -252,3 +254,81 @@ fn test_call_deprecated_function() -> Result<()> { // assert_eq!(Some(4875), move_abort_code(status)); Ok(()) } + +#[stest::test] +fn test_stm_dependency() -> Result<()> { + let (chain_state, net) = prepare_genesis(); + let account1 = Account::new(); + let txn1 = Transaction::UserTransaction(create_account_txn_sent_as_association( + &account1, 0, 50_000_000, 1, &net, + )); + let output1 = execute_and_apply(&chain_state, txn1); + assert_eq!(KeptVMStatus::Executed, output1.status().status().unwrap()); + let account2 = Account::new(); + let txn2 = Transaction::UserTransaction(account1.sign_txn( + starcoin_transaction_builder::build_transfer_txn( + *account1.address(), + *account2.address(), + 0, + 1000, + 1, + DEFAULT_MAX_GAS_AMOUNT, + net.time_service().now_secs() + DEFAULT_EXPIRATION_TIME, + net.chain_id(), + ), + )); + let output2 = execute_and_apply(&chain_state, txn2); + assert_eq!(KeptVMStatus::Executed, output2.status().status().unwrap()); + let txn3 = Transaction::UserTransaction(account1.sign_txn( + starcoin_transaction_builder::build_transfer_txn( + *account1.address(), + *account2.address(), + 1, + 1000, + 1, + DEFAULT_MAX_GAS_AMOUNT, + net.time_service().now_secs() + DEFAULT_EXPIRATION_TIME, + net.chain_id(), + ), + )); + let txn4 = Transaction::UserTransaction(account1.sign_txn( + starcoin_transaction_builder::build_transfer_txn( + *account1.address(), + *account2.address(), + 2, + 1000, + 1, + DEFAULT_MAX_GAS_AMOUNT, + net.time_service().now_secs() + DEFAULT_EXPIRATION_TIME, + net.chain_id(), + ), + )); + // + // let txn5 = Transaction::UserTransaction(account1.sign_txn( + // starcoin_transaction_builder::build_transfer_txn( + // *account1.address(), + // *account2.address(), + // 1, + // 1000, + // 1, + // DEFAULT_MAX_GAS_AMOUNT, + // net.time_service().now_secs() + DEFAULT_EXPIRATION_TIME, + // net.chain_id(), + // ), + // )); + StarcoinVM::set_concurrency_level_once(4); + let outputs = + starcoin_executor::execute_transactions(&chain_state, vec![txn3, txn4], None).unwrap(); + outputs.into_iter().for_each(|output| { + if let TransactionStatus::Keep(_) = output.status() { + chain_state + .apply_write_set(output.write_set().clone()) + .expect("apply write_set should success."); + chain_state.commit().expect("commit should success."); + } + }); + let balance = get_balance(*account2.address(), &chain_state); + + assert_eq!(balance, 3000); + Ok(()) +} diff --git a/vm/transaction-benchmarks/src/transactions.rs b/vm/transaction-benchmarks/src/transactions.rs index e53a862858..10f46bb829 100644 --- a/vm/transaction-benchmarks/src/transactions.rs +++ b/vm/transaction-benchmarks/src/transactions.rs @@ -11,12 +11,12 @@ use starcoin_crypto::HashValue; use std::time::{Instant, SystemTime}; use starcoin_language_e2e_tests::account::AccountData; +use starcoin_language_e2e_tests::common_transactions::duration_since_epoch; use starcoin_language_e2e_tests::{ account_universe::{log_balance_strategy, AUTransactionGen, AccountUniverseGen}, executor::FakeExecutor, gas_costs::TXN_RESERVED, }; -use starcoin_language_e2e_tests::common_transactions::duration_since_epoch; use starcoin_types::{block_metadata::BlockMetadata, transaction::Transaction}; From 13a646aa5605990998f70e211526bdc0d3c9074f Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Thu, 28 Sep 2023 21:48:54 +0800 Subject: [PATCH 44/89] [e2e-test] fix error EPROLOGUE_CANT_PAY_GAS_DEPOSIT --- vm/e2e-tests/src/gas_costs.rs | 13 ++++-- vm/transaction-benchmarks/src/lib.rs | 3 ++ .../src/test_peer_to_peer.rs | 45 +++++++++++++++++++ vm/transaction-benchmarks/src/transactions.rs | 4 +- 4 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 vm/transaction-benchmarks/src/test_peer_to_peer.rs diff --git a/vm/e2e-tests/src/gas_costs.rs b/vm/e2e-tests/src/gas_costs.rs index c491ca2973..99c919aee3 100644 --- a/vm/e2e-tests/src/gas_costs.rs +++ b/vm/e2e-tests/src/gas_costs.rs @@ -13,7 +13,7 @@ use starcoin_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, Uniform}; use starcoin_vm_types::transaction::{authenticator::AuthenticationKey, SignedUserTransaction}; /// The gas each transaction is configured to reserve. If the gas available in the account, -/// converted to microaptos, falls below this threshold, transactions are expected to fail with +/// converted to micro STC, falls below this threshold, transactions are expected to fail with /// an insufficient balance. pub const TXN_RESERVED: u64 = 500_000; @@ -133,12 +133,17 @@ pub static CREATE_EXISTING_ACCOUNT_NEXT: Lazy = Lazy::new(|| { pub static PEER_TO_PEER: Lazy = Lazy::new(|| { // Compute gas used by running a placeholder transaction. let mut executor = FakeExecutor::from_genesis_file(); - let sender = AccountData::new(1_000_000, 10); - let receiver = AccountData::new(1_000_000, 10); + // XXX FIXME YSG + // let sender = AccountData::new(1_000_000, 10); + // let receiver = AccountData::new(1_000_000, 10); + let sender = AccountData::new(1_000_000_000, 10); + let receiver = AccountData::new(1_000_000_000, 10); executor.add_account_data(&sender); executor.add_account_data(&receiver); - let txn = peer_to_peer_txn(sender.account(), receiver.account(), 10, 20_000); + // XXX FIXME YSG + // let txn = peer_to_peer_txn(sender.account(), receiver.account(), 10, 20_000); + let txn = peer_to_peer_txn(sender.account(), receiver.account(), 10, 10); compute_gas_used(txn, &mut executor) }); diff --git a/vm/transaction-benchmarks/src/lib.rs b/vm/transaction-benchmarks/src/lib.rs index 723e0620bf..1191e8b4c8 100644 --- a/vm/transaction-benchmarks/src/lib.rs +++ b/vm/transaction-benchmarks/src/lib.rs @@ -8,3 +8,6 @@ pub mod measurement; #[cfg(any(test, feature = "fuzzing"))] pub mod transactions; + +#[cfg(test)] +mod test_peer_to_peer; diff --git a/vm/transaction-benchmarks/src/test_peer_to_peer.rs b/vm/transaction-benchmarks/src/test_peer_to_peer.rs new file mode 100644 index 0000000000..d73b09172c --- /dev/null +++ b/vm/transaction-benchmarks/src/test_peer_to_peer.rs @@ -0,0 +1,45 @@ +// Copyright (c) The Starcoin Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use crate::transactions::TransactionBencher; +use proptest::arbitrary::any_with; +use starcoin_language_e2e_tests::account::AccountData; +use starcoin_language_e2e_tests::account_universe::P2PTransferGen; +use starcoin_language_e2e_tests::common_transactions::peer_to_peer_txn; +use starcoin_language_e2e_tests::executor::FakeExecutor; + +#[test] +pub fn bencher_sequence() { + let default_num_account = 2; + let default_num_transactions = 1; + let maxium_transfer_balance = 100; + let minium_transfer_balance = 10; + + let bencher = TransactionBencher::new( + any_with::((minium_transfer_balance, maxium_transfer_balance)), + default_num_account, + default_num_transactions, + ); + bencher.manual_sequence(default_num_account, default_num_transactions, 1, 1); +} + +#[test] +pub fn fake_execute_with_account_data() { + // Compute gas used by running a placeholder transaction. + let mut executor = FakeExecutor::from_genesis_file(); + let sender = AccountData::new(1_000_000_000, 10); + let receiver = AccountData::new(1_000_000_000, 10); + executor.add_account_data(&sender); + executor.add_account_data(&receiver); + + let txn = peer_to_peer_txn(sender.account(), receiver.account(), 10, 10); + let result = executor.execute_block(vec![txn]); + match result { + Ok(outputs) => { + println!("Outputs: {:#?}", outputs); + } + Err(err) => { + println!("Error: {:#?}", err); + } + } +} diff --git a/vm/transaction-benchmarks/src/transactions.rs b/vm/transaction-benchmarks/src/transactions.rs index 10f46bb829..83e4ba158e 100644 --- a/vm/transaction-benchmarks/src/transactions.rs +++ b/vm/transaction-benchmarks/src/transactions.rs @@ -372,7 +372,9 @@ fn universe_strategy( num_transactions: usize, ) -> impl Strategy { // Multiply by 5 past the number of to provide - let max_balance = TXN_RESERVED * num_transactions as u64 * 5; + // XXX FIXME YSG + // let max_balance = TXN_RESERVED * num_transactions as u64 * 5; + let max_balance = 5_000_000_000; let balance_strategy = log_balance_strategy(max_balance); AccountUniverseGen::strategy(num_accounts, balance_strategy) } From d103e58a59664210124adc823d8d792d03f1263f Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Mon, 2 Oct 2023 14:13:57 +0800 Subject: [PATCH 45/89] close some log --- scripts/benchmark_parallel.sh | 6 +++--- vm/e2e-tests/src/data_store.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/benchmark_parallel.sh b/scripts/benchmark_parallel.sh index 5c15afe5a2..e302a679d7 100755 --- a/scripts/benchmark_parallel.sh +++ b/scripts/benchmark_parallel.sh @@ -3,8 +3,8 @@ #RUST_LOG=info cargo bench --features fuzzing -p 'starcoin-transaction-benchmarks' STARCOIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd .. && pwd)" -TXN_NUMS=1000,10000,50000,100000 -ACCOUNT_NUMS=2,10,100,1000,10000 +TXN_NUMS=500000 +ACCOUNT_NUMS=10000 if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux @@ -39,4 +39,4 @@ IFS=',' power_of_two_str="${power_of_two_array[*]}" #echo "Power of two array: ${power_of_two_str[@]}" -eval RUST_LOG=info cargo run --release -p "starcoin-transaction-benchmarks" --features fuzzing -- --concurrency-level "$power_of_two_str" --txn-nums "$TXN_NUMS" --account-nums="$ACCOUNT_NUMS" \ No newline at end of file +eval RUST_LOG=info cargo run --release -p "starcoin-transaction-benchmarks" --features fuzzing -- --concurrency-level "8" --txn-nums "$TXN_NUMS" --account-nums="$ACCOUNT_NUMS" \ No newline at end of file diff --git a/vm/e2e-tests/src/data_store.rs b/vm/e2e-tests/src/data_store.rs index d2bf7d44bb..8d62b54409 100644 --- a/vm/e2e-tests/src/data_store.rs +++ b/vm/e2e-tests/src/data_store.rs @@ -46,7 +46,7 @@ impl FakeDataStore { /// Adds a [`WriteSet`] to this data store. pub fn add_write_set(&self, write_set: &WriteSet) { - println!("FakeDataStore::add_write_set | {:#?}", write_set); + //println!("FakeDataStore::add_write_set | {:#?}", write_set); let mut write_handle = self.state_data.write().expect("Panic for lock"); for (state_key, write_op) in write_set { @@ -101,7 +101,7 @@ impl FakeDataStore { // TODO: only the "sync" get is implemented impl StateView for FakeDataStore { fn get_state_value(&self, state_key: &StateKey) -> Result>> { - println!("StateView::get_state_value, state_key: {:#?}", state_key); + //println!("StateView::get_state_value, state_key: {:#?}", state_key); Ok(self.inner().get(state_key).cloned()) } From 1f6f589cf323bae7cf06bc709d66a1c2b2847eb9 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Wed, 4 Oct 2023 09:52:23 +0800 Subject: [PATCH 46/89] add log --- vm/transaction-benchmarks/log_1000_50000 | 2556 +++++++++++++++++ vm/transaction-benchmarks/src/main.rs | 6 +- vm/transaction-benchmarks/src/transactions.rs | 162 +- vm/vm-runtime/src/errors.rs | 2 +- vm/vm-runtime/src/starcoin_vm.rs | 1 + 5 files changed, 2583 insertions(+), 144 deletions(-) create mode 100644 vm/transaction-benchmarks/log_1000_50000 diff --git a/vm/transaction-benchmarks/log_1000_50000 b/vm/transaction-benchmarks/log_1000_50000 new file mode 100644 index 0000000000..96ed1fcfb9 --- /dev/null +++ b/vm/transaction-benchmarks/log_1000_50000 @@ -0,0 +1,2556 @@ + Running `/Users/yesonggao/Github/starcoin_bak/target/release/starcoin-transaction-benchmarks --concurrency-level 8 --txn-nums 50000 --account-nums=1000` +num cpus = 8, run_seq: true, run_seq: true +=========== concurrency_level: 8 started =========== +=== accounts_num: 1000 started === + +WARMUP - ignore results +Parallel execution starts... +YSG BlockMetadata +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +Parallel execution finishes, TPS = 4430 +Sequential execution starts... +Sequential execution finishes, TPS = 3131 +WARMUP - ignore results +Parallel execution starts... +YSG BlockMetadata +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +Parallel execution finishes, TPS = 4716 +Sequential execution starts... +Sequential execution finishes, TPS = 3484 +RUN benchmark for: num_threads = 8, num_account = 1000, block_size = 50000 +Parallel execution starts... +YSG BlockMetadata +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +Parallel execution finishes, TPS = 4748 +Sequential execution starts... +Sequential execution finishes, TPS = 3234 +RUN benchmark for: num_threads = 8, num_account = 1000, block_size = 50000 +Parallel execution starts... +YSG BlockMetadata +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +Parallel execution finishes, TPS = 4678 +Sequential execution starts... +Sequential execution finishes, TPS = 3355 +RUN benchmark for: num_threads = 8, num_account = 1000, block_size = 50000 +Parallel execution starts... +YSG BlockMetadata +YSG TRANSACTION_EXPIRED +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +Parallel execution finishes, TPS = 4867 +Sequential execution starts... +Sequential execution finishes, TPS = 3498 +RUN benchmark for: num_threads = 8, num_account = 1000, block_size = 50000 +Parallel execution starts... +YSG BlockMetadata +YSG TRANSACTION_EXPIRED +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +Parallel execution finishes, TPS = 5128 +Sequential execution starts... +Sequential execution finishes, TPS = 3633 +RUN benchmark for: num_threads = 8, num_account = 1000, block_size = 50000 +Parallel execution starts... +YSG BlockMetadata +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +Parallel execution finishes, TPS = 5176 +Sequential execution starts... +Sequential execution finishes, TPS = 3563 +RUN benchmark for: num_threads = 8, num_account = 1000, block_size = 50000 +Parallel execution starts... +YSG BlockMetadata +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +Parallel execution finishes, TPS = 5152 +Sequential execution starts... +Sequential execution finishes, TPS = 3687 +RUN benchmark for: num_threads = 8, num_account = 1000, block_size = 50000 +Parallel execution starts... +YSG BlockMetadata +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +Parallel execution finishes, TPS = 5226 +Sequential execution starts... +Sequential execution finishes, TPS = 3751 +RUN benchmark for: num_threads = 8, num_account = 1000, block_size = 50000 +Parallel execution starts... +YSG BlockMetadata +YSG SEQUENCE_NUMBER_TOO_NEW +YSG TRANSACTION_EXPIRED +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +Parallel execution finishes, TPS = 5206 +Sequential execution starts... +Sequential execution finishes, TPS = 3705 +RUN benchmark for: num_threads = 8, num_account = 1000, block_size = 50000 +Parallel execution starts... +YSG BlockMetadata +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +Parallel execution finishes, TPS = 5266 +Sequential execution starts... +Sequential execution finishes, TPS = 3711 +RUN benchmark for: num_threads = 8, num_account = 1000, block_size = 50000 +Parallel execution starts... +YSG BlockMetadata +YSG TRANSACTION_EXPIRED +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +YSG SEQUENCE_NUMBER_TOO_NEW +Parallel execution finishes, TPS = 5138 +Sequential execution starts... +Sequential execution finishes, TPS = 3395 +=== accounts_num: 1000 completed === +PARAMS: num_account = 1000, block_size = 50000 +Sequential TPS: [3234, 3355, 3395, 3498, 3563, 3633, 3687, 3705, 3711, 3751] +Avg Sequential TPS = 3553 +Parallel TPS: [4678, 4748, 4867, 5128, 5138, 5152, 5176, 5206, 5226, 5266] +Avg Parallel TPS = 5058 +Speed up 1x over sequential +=========== concurrency_level: 8 finished =========== diff --git a/vm/transaction-benchmarks/src/main.rs b/vm/transaction-benchmarks/src/main.rs index c185b1feb6..39536f4a4d 100644 --- a/vm/transaction-benchmarks/src/main.rs +++ b/vm/transaction-benchmarks/src/main.rs @@ -54,11 +54,7 @@ fn main() { // run_par = true; // } - let bencher = TransactionBencher::new( - any_with::((1_000, 1_000_000)), - default_num_accounts, - default_num_transactions, - ); + let bencher = TransactionBencher::new(any_with::((1_000, 1_000_000))); // let acts = [1000]; //let txns = [10000, 50000, 100000]; diff --git a/vm/transaction-benchmarks/src/transactions.rs b/vm/transaction-benchmarks/src/transactions.rs index 83e4ba158e..4666e65d1a 100644 --- a/vm/transaction-benchmarks/src/transactions.rs +++ b/vm/transaction-benchmarks/src/transactions.rs @@ -38,16 +38,16 @@ where S::Value: AUTransactionGen, { /// The number of accounts created by default. - //pub const DEFAULT_NUM_ACCOUNTS: usize = 1000; + pub const DEFAULT_NUM_ACCOUNTS: usize = 1000; /// The number of transactions created by default. - // pub const DEFAULT_NUM_TRANSACTIONS: usize = 1000; + pub const DEFAULT_NUM_TRANSACTIONS: usize = 1000; /// Creates a new transaction bencher with default settings. - pub fn new(strategy: S, num_accounts: usize, num_transactions: usize) -> Self { + pub fn new(strategy: S) -> Self { Self { - num_accounts, - num_transactions, + num_accounts: Self::DEFAULT_NUM_ACCOUNTS, + num_transactions: Self::DEFAULT_NUM_TRANSACTIONS, strategy, } } @@ -82,23 +82,18 @@ where /// Runs the bencher. pub fn bench_parallel(&self, b: &mut Bencher) { - let start_time = SystemTime::now(); - let num = 8; b.iter_batched( || { - ParallelBenchState::with_size( + TransactionBenchState::with_size( &self.strategy, self.num_accounts, self.num_transactions, - num, ) }, - |state| state.execute(), + |state| state.execute_parallel(), // The input here is the entire list of signed transactions, so it's pretty large. BatchSize::LargeInput, - ); - let use_time = SystemTime::now().duration_since(start_time).unwrap(); - println!("cpu num = {}, cost time = {}", num, use_time.as_secs()); + ) } /// Runs the bencher. @@ -137,71 +132,6 @@ where (par_tps, seq_tps) } - - pub fn manual_sequence( - &self, - num_accounts: usize, - num_txn: usize, - num_warmups: usize, - num_runs: usize, - concurrency_level: usize, - ) -> Vec { - let mut ret = Vec::new(); - - let total_runs = num_warmups + num_runs; - for i in 0..total_runs { - let state = TransactionBenchState::with_size(&self.strategy, num_accounts, num_txn); - - if i < num_warmups { - println!("WARMUP - ignore results"); - state.execute(); - } else { - println!( - "RUN bencher for: num_threads = {}, \ - block_size = {}, \ - num_account = {}", - concurrency_level, num_txn, num_accounts, - ); - ret.push(state.execute()); - } - } - ret - } - - pub fn manual_parallel( - &self, - num_accounts: usize, - num_txn: usize, - num_warmups: usize, - num_runs: usize, - concurrency_level: usize, - ) -> Vec { - let mut ret = Vec::new(); - - let total_runs = num_warmups + num_runs; - for i in 0..total_runs { - let state = ParallelBenchState::with_size( - &self.strategy, - num_accounts, - num_txn, - concurrency_level, - ); - - if i < num_warmups { - println!("WARMUP - ignore results"); - state.execute(); - } else { - println!( - "RUN bencher for: num_threads = {}, \ - block_size = {}, \ - num_account = {}", - concurrency_level, num_txn, num_accounts, - ); - ret.push(state.execute()); - } - } - ret - } } struct TransactionBenchState { @@ -336,19 +266,19 @@ impl TransactionBenchState { transactions_len * 1000 / exec_t.as_millis() as usize } - // /// Executes this state in a single block via parallel execution. - // fn execute_parallel(self) { - // // The output is ignored here since we're just testing transaction performance, not trying - // // to assert correctness. - // ParallelStarcoinVM::execute_block( - // self.transactions, - // self.executor.get_state_view(), - // num_cpus::get(), - // None, - // None, - // ) - // .expect("VM should not fail to start"); - // } + /// Executes this state in a single block via parallel execution. + fn execute_parallel(self) { + // The output is ignored here since we're just testing transaction performance, not trying + // to assert correctness. + BlockStarcoinVM::execute_block( + self.transactions, + self.executor.get_state_view(), + num_cpus::get(), + None, + None, + ) + .expect("VM should not fail to start"); + } fn execute_blockstm_benchmark( self, @@ -374,52 +304,8 @@ fn universe_strategy( // Multiply by 5 past the number of to provide // XXX FIXME YSG // let max_balance = TXN_RESERVED * num_transactions as u64 * 5; - let max_balance = 5_000_000_000; - let balance_strategy = log_balance_strategy(max_balance); - AccountUniverseGen::strategy(num_accounts, balance_strategy) + // let max_balance = 5_000_000_000; + let balance = TXN_RESERVED * num_transactions as u64 * 5; + AccountUniverseGen::strategy(num_accounts, balance..(balance + 1)) } -struct ParallelBenchState { - bench_state: TransactionBenchState, - num_threads: usize, -} - -impl ParallelBenchState { - /// Creates a new benchmark state with the given number of accounts and transactions. - fn with_size( - strategy: S, - num_accounts: usize, - num_transactions: usize, - num_threads: usize, - ) -> Self - where - S: Strategy, - S::Value: AUTransactionGen, - { - Self { - bench_state: TransactionBenchState::with_universe( - strategy, - universe_strategy(num_accounts, num_transactions), - num_transactions, - ), - num_threads, - } - } - - fn execute(self) -> usize { - // let txns = self - // .bench_state - // .transactions - // .into_iter() - // .map(Transaction::UserTransaction) - // .collect(); - - let state_view = self.bench_state.executor.get_state_view(); - // measured - microseconds. - BlockStarcoinVM::execute_block_tps( - self.bench_state.transactions.clone(), - state_view, - self.num_threads, - ) - } -} diff --git a/vm/vm-runtime/src/errors.rs b/vm/vm-runtime/src/errors.rs index 442c43ff1e..91d035572d 100644 --- a/vm/vm-runtime/src/errors.rs +++ b/vm/vm-runtime/src/errors.rs @@ -43,7 +43,6 @@ pub fn error_split(code: u64) -> (u8, u64) { } pub fn convert_prologue_runtime_error(error: VMError) -> Result<(), VMStatus> { - println!("convert_prologue_runtime_error VMError: {:#?}", error); let status = error.into_vm_status(); Err(match status { VMStatus::Executed => VMStatus::Executed, @@ -97,6 +96,7 @@ pub fn convert_prologue_runtime_error(error: VMError) -> Result<(), VMStatus> { StatusCode::UNEXPECTED_ERROR_FROM_KNOWN_MOVE_FUNCTION } }; + println!("YSG {:#?}", new_major_status); VMStatus::Error(new_major_status) } status @ VMStatus::ExecutionFailure { .. } | status @ VMStatus::Error(_) => { diff --git a/vm/vm-runtime/src/starcoin_vm.rs b/vm/vm-runtime/src/starcoin_vm.rs index fd4d005771..2c2d6c6097 100644 --- a/vm/vm-runtime/src/starcoin_vm.rs +++ b/vm/vm-runtime/src/starcoin_vm.rs @@ -1615,6 +1615,7 @@ impl VMAdapter for StarcoinVM { (vm_status, output, Some(sender)) } PreprocessedTransaction::BlockMetadata(block_meta) => { + println!("YSG BlockMetadata"); let (vm_status, output) = match self.process_block_metadata(data_cache, block_meta.clone()) { Ok(output) => (VMStatus::Executed, output), From f7a416eb0e473dde830fd828dafc3a2397ec0807 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Wed, 4 Oct 2023 13:40:12 +0800 Subject: [PATCH 47/89] add branches --- .github/workflows/build_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 19642f7200..cab879c561 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -3,7 +3,7 @@ on: workflow_dispatch: pull_request: branches: - - block_executor_optimize_tps + - block_executor_optimize_tps_debug jobs: build-and-test: From 4e53ce53a9eccb21b52a0116b216c30a32eeef9c Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Wed, 4 Oct 2023 14:10:41 +0800 Subject: [PATCH 48/89] add bench-num --- scripts/benchmark_parallel.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/benchmark_parallel.sh b/scripts/benchmark_parallel.sh index e302a679d7..7b8477649b 100755 --- a/scripts/benchmark_parallel.sh +++ b/scripts/benchmark_parallel.sh @@ -39,4 +39,4 @@ IFS=',' power_of_two_str="${power_of_two_array[*]}" #echo "Power of two array: ${power_of_two_str[@]}" -eval RUST_LOG=info cargo run --release -p "starcoin-transaction-benchmarks" --features fuzzing -- --concurrency-level "8" --txn-nums "$TXN_NUMS" --account-nums="$ACCOUNT_NUMS" \ No newline at end of file +eval RUST_LOG=info cargo run --release -p "starcoin-transaction-benchmarks" --features fuzzing -- --concurrency-level "16" --txn-nums "$TXN_NUMS" --account-nums="$ACCOUNT_NUMS" \ No newline at end of file From 474dc1044348be45abc888f20dd660a46f46fa43 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Wed, 4 Oct 2023 14:51:50 +0800 Subject: [PATCH 49/89] remove log --- vm/vm-runtime/src/errors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/vm-runtime/src/errors.rs b/vm/vm-runtime/src/errors.rs index 91d035572d..4ada4eb68f 100644 --- a/vm/vm-runtime/src/errors.rs +++ b/vm/vm-runtime/src/errors.rs @@ -96,7 +96,7 @@ pub fn convert_prologue_runtime_error(error: VMError) -> Result<(), VMStatus> { StatusCode::UNEXPECTED_ERROR_FROM_KNOWN_MOVE_FUNCTION } }; - println!("YSG {:#?}", new_major_status); + // println!("YSG {:#?}", new_major_status); VMStatus::Error(new_major_status) } status @ VMStatus::ExecutionFailure { .. } | status @ VMStatus::Error(_) => { From 1561a3519bbbc863ea7b3cee50da13581e4c4c62 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Wed, 4 Oct 2023 15:16:39 +0800 Subject: [PATCH 50/89] add ACCOUNT_NUMS --- scripts/benchmark_parallel.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/benchmark_parallel.sh b/scripts/benchmark_parallel.sh index 7b8477649b..f881b6cbfb 100755 --- a/scripts/benchmark_parallel.sh +++ b/scripts/benchmark_parallel.sh @@ -4,7 +4,7 @@ STARCOIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd .. && pwd)" TXN_NUMS=500000 -ACCOUNT_NUMS=10000 +ACCOUNT_NUMS=1000000 if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux From 7949e0df2c8b30043d161a822bf3f3d54064a41e Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Thu, 5 Oct 2023 00:15:55 +0800 Subject: [PATCH 51/89] fix transaction txn --- vm/e2e-tests/src/common_transactions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/e2e-tests/src/common_transactions.rs b/vm/e2e-tests/src/common_transactions.rs index d1bd529904..e388ad3c79 100644 --- a/vm/e2e-tests/src/common_transactions.rs +++ b/vm/e2e-tests/src/common_transactions.rs @@ -103,7 +103,7 @@ pub fn peer_to_peer_txn( &starcoin_acc, receiver.address(), seq_num, - duration_since_epoch().as_secs() + 100, + duration_since_epoch().as_secs() + DEFAULT_EXPIRATION_TIME, transfer_amount as u128, &ChainNetwork::new_test(), ) From 2c932c5be3bf5381aedd34c9737e41ff20812d2a Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Thu, 5 Oct 2023 15:26:11 +0800 Subject: [PATCH 52/89] update some constants --- vm/e2e-tests/src/gas_costs.rs | 9 +++------ vm/transaction-builder/src/lib.rs | 4 ++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/vm/e2e-tests/src/gas_costs.rs b/vm/e2e-tests/src/gas_costs.rs index 99c919aee3..88f1266c8c 100644 --- a/vm/e2e-tests/src/gas_costs.rs +++ b/vm/e2e-tests/src/gas_costs.rs @@ -134,16 +134,13 @@ pub static PEER_TO_PEER: Lazy = Lazy::new(|| { // Compute gas used by running a placeholder transaction. let mut executor = FakeExecutor::from_genesis_file(); // XXX FIXME YSG - // let sender = AccountData::new(1_000_000, 10); - // let receiver = AccountData::new(1_000_000, 10); - let sender = AccountData::new(1_000_000_000, 10); - let receiver = AccountData::new(1_000_000_000, 10); + let sender = AccountData::new(1_000_000, 10); + let receiver = AccountData::new(1_000_000, 10); executor.add_account_data(&sender); executor.add_account_data(&receiver); // XXX FIXME YSG - // let txn = peer_to_peer_txn(sender.account(), receiver.account(), 10, 20_000); - let txn = peer_to_peer_txn(sender.account(), receiver.account(), 10, 10); + let txn = peer_to_peer_txn(sender.account(), receiver.account(), 10, 20_000); compute_gas_used(txn, &mut executor) }); diff --git a/vm/transaction-builder/src/lib.rs b/vm/transaction-builder/src/lib.rs index 456b5a1387..dfdb6c4754 100644 --- a/vm/transaction-builder/src/lib.rs +++ b/vm/transaction-builder/src/lib.rs @@ -318,8 +318,8 @@ pub fn peer_to_peer_v2( bcs_ext::to_bytes(&amount).unwrap(), ], )), - 10000000, - 1, + 500000, + 0, expiration_timestamp_secs, net.chain_id(), )) From 204a8760092e0473ac36736c9f4f1d1af2ab577a Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Thu, 5 Oct 2023 18:47:06 +0800 Subject: [PATCH 53/89] update TurboSTM validate --- .github/workflows/build_test.yml | 2 +- Cargo.lock | 1 + scripts/benchmark_parallel.sh | 2 +- vm/block-executor/Cargo.toml | 1 + vm/block-executor/src/executor.rs | 49 +- vm/block-executor/src/scheduler.rs | 601 ++++++++++++------ vm/transaction-benchmarks/src/transactions.rs | 27 +- vm/types/src/write_set.rs | 18 + 8 files changed, 458 insertions(+), 243 deletions(-) diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index cab879c561..f1c503deeb 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -3,7 +3,7 @@ on: workflow_dispatch: pull_request: branches: - - block_executor_optimize_tps_debug + - block_executor_optimize_tps_validate jobs: build-and-test: diff --git a/Cargo.lock b/Cargo.lock index 3df460d0c5..683a13a254 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9254,6 +9254,7 @@ dependencies = [ "dashmap", "num_cpus", "once_cell", + "parking_lot 0.12.1", "proptest", "proptest-derive", "rayon", diff --git a/scripts/benchmark_parallel.sh b/scripts/benchmark_parallel.sh index f881b6cbfb..5248d1d977 100755 --- a/scripts/benchmark_parallel.sh +++ b/scripts/benchmark_parallel.sh @@ -39,4 +39,4 @@ IFS=',' power_of_two_str="${power_of_two_array[*]}" #echo "Power of two array: ${power_of_two_str[@]}" -eval RUST_LOG=info cargo run --release -p "starcoin-transaction-benchmarks" --features fuzzing -- --concurrency-level "16" --txn-nums "$TXN_NUMS" --account-nums="$ACCOUNT_NUMS" \ No newline at end of file +eval RUST_LOG=info cargo run --release -p "starcoin-transaction-benchmarks" --features fuzzing -- --concurrency-level "24" --txn-nums "$TXN_NUMS" --account-nums="$ACCOUNT_NUMS" \ No newline at end of file diff --git a/vm/block-executor/Cargo.toml b/vm/block-executor/Cargo.toml index d8062ef10b..4aca877573 100644 --- a/vm/block-executor/Cargo.toml +++ b/vm/block-executor/Cargo.toml @@ -26,6 +26,7 @@ criterion = { workspace = true, optional = true } proptest = { workspace = true, optional = true } proptest-derive = { workspace = true, optional = true } starcoin-vm-types = { workspace = true } +parking_lot = { workspace = true } [dev-dependencies] criterion = { workspace = true } diff --git a/vm/block-executor/src/executor.rs b/vm/block-executor/src/executor.rs index b54033aca9..fc686ba2e7 100644 --- a/vm/block-executor/src/executor.rs +++ b/vm/block-executor/src/executor.rs @@ -4,7 +4,7 @@ use crate::errors::Error::BlockRestart; use crate::{ errors::*, - scheduler::{Scheduler, SchedulerTask, TaskGuard, TxnIndex, Version}, + scheduler::{Scheduler, SchedulerTask, TxnIndex, Version, Wave}, task::{ExecutionStatus, ExecutorTask, ModulePath, Transaction, TransactionOutput}, txn_last_input_output::{ReadDescriptor, TxnLastInputOutput}, }; @@ -12,6 +12,7 @@ use num_cpus; use once_cell::sync::Lazy; use starcoin_infallible::Mutex; use starcoin_mvhashmap::MVHashMap; +use std::sync::atomic::{AtomicBool, Ordering}; use std::{collections::HashSet, hash::Hash, marker::PhantomData, sync::Arc, thread::spawn}; pub static RAYON_EXEC_POOL: Lazy = Lazy::new(|| { @@ -127,10 +128,9 @@ where } } - fn execute<'a>( + fn execute( &self, version: Version, - guard: TaskGuard<'a>, signature_verified_block: &[T], last_input_output: &TxnLastInputOutput< ::Key, @@ -138,9 +138,9 @@ where ::Error, >, versioned_data_cache: &MVHashMap<::Key, ::Value>, - scheduler: &'a Scheduler, + scheduler: &Scheduler, executor: &E, - ) -> SchedulerTask<'a> { + ) -> SchedulerTask { let (idx_to_execute, incarnation) = version; let txn = &signature_verified_block[idx_to_execute]; @@ -194,21 +194,21 @@ where } last_input_output.record(idx_to_execute, state_view.take_reads(), result); - scheduler.finish_execution(idx_to_execute, incarnation, writes_outside, guard) + scheduler.finish_execution(idx_to_execute, incarnation, writes_outside) } - fn validate<'a>( + fn validate( &self, version_to_validate: Version, - guard: TaskGuard<'a>, + validation_wave: Wave, last_input_output: &TxnLastInputOutput< ::Key, ::Output, ::Error, >, versioned_data_cache: &MVHashMap<::Key, ::Value>, - scheduler: &'a Scheduler, - ) -> SchedulerTask<'a> { + scheduler: &Scheduler, + ) -> SchedulerTask { let (idx_to_validate, incarnation) = version_to_validate; let read_set = last_input_output .read_set(idx_to_validate) @@ -230,8 +230,9 @@ where versioned_data_cache.mark_estimate(k, idx_to_validate); } - scheduler.finish_abort(idx_to_validate, incarnation, guard) + scheduler.finish_abort(idx_to_validate, incarnation) } else { + scheduler.finish_validation(idx_to_validate, validation_wave); SchedulerTask::NoTask } } @@ -247,30 +248,41 @@ where >, versioned_data_cache: &MVHashMap<::Key, ::Value>, scheduler: &Scheduler, + committing: bool, ) { // Make executor for each task. TODO: fast concurrent executor. let executor = E::init(*executor_arguments); let mut scheduler_task = SchedulerTask::NoTask; loop { + // Only one thread try_commit to avoid contention. + if committing { + // Keep committing txns until there is no more that can be committed now. + while let Some(txn_idx) = scheduler.try_commit() { + if txn_idx + 1 == block.len() { + // Committed the last transaction / everything. + scheduler_task = SchedulerTask::Done; + break; + } + } + } scheduler_task = match scheduler_task { - SchedulerTask::ValidationTask(version_to_validate, guard) => self.validate( + SchedulerTask::ValidationTask(version_to_validate, wave) => self.validate( version_to_validate, - guard, + wave, last_input_output, versioned_data_cache, scheduler, ), - SchedulerTask::ExecutionTask(version_to_execute, None, guard) => self.execute( + SchedulerTask::ExecutionTask(version_to_execute, None) => self.execute( version_to_execute, - guard, block, last_input_output, versioned_data_cache, scheduler, &executor, ), - SchedulerTask::ExecutionTask(_, Some(condvar), _guard) => { + SchedulerTask::ExecutionTask(_, Some(condvar)) => { let (lock, cvar) = &*condvar; // Mark dependency resolved. *lock.lock() = true; @@ -279,7 +291,7 @@ where SchedulerTask::NoTask } - SchedulerTask::NoTask => scheduler.next_task(), + SchedulerTask::NoTask => scheduler.next_task(committing), SchedulerTask::Done => { break; } @@ -299,6 +311,7 @@ where let num_txns = signature_verified_block.len(); let versioned_data_cache = MVHashMap::new(); let last_input_output = TxnLastInputOutput::new(num_txns); + let committing = AtomicBool::new(true); let scheduler = Scheduler::new(num_txns); RAYON_EXEC_POOL.scope(|s| { @@ -310,13 +323,13 @@ where &last_input_output, &versioned_data_cache, &scheduler, + committing.swap(false, Ordering::SeqCst), ); }); } }); // TODO: for large block sizes and many cores, extract outputs in parallel. - let num_txns = scheduler.num_txn_to_execute(); let mut final_results = Vec::with_capacity(num_txns); let maybe_err = if last_input_output.module_publishing_may_race() { Some(Error::ModulePathReadWrite) diff --git a/vm/block-executor/src/scheduler.rs b/vm/block-executor/src/scheduler.rs index 1daa40c757..3d4d2e15bd 100644 --- a/vm/block-executor/src/scheduler.rs +++ b/vm/block-executor/src/scheduler.rs @@ -2,52 +2,43 @@ // SPDX-License-Identifier: Apache-2.0 use crossbeam::utils::CachePadded; +use parking_lot::{RwLock, RwLockUpgradableReadGuard}; use starcoin_infallible::Mutex; use std::{ - cmp::min, + cmp::{max, min}, hint, + ops::DerefMut, sync::{ - atomic::{AtomicBool, AtomicUsize, Ordering}, + atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering}, Arc, Condvar, }, }; +const TXN_IDX_MASK: u64 = (1 << 32) - 1; + // Type aliases. pub type TxnIndex = usize; pub type Incarnation = usize; +pub type Wave = u32; pub type Version = (TxnIndex, Incarnation); type DependencyCondvar = Arc<(Mutex, Condvar)>; -// A struct to track the number of active tasks in the scheduler using RAII. -pub struct TaskGuard<'a> { - counter: &'a AtomicUsize, -} - -impl<'a> TaskGuard<'a> { - pub fn new(counter: &'a AtomicUsize) -> Self { - counter.fetch_add(1, Ordering::SeqCst); - Self { counter } - } -} - -impl Drop for TaskGuard<'_> { - fn drop(&mut self) { - assert!(self.counter.fetch_sub(1, Ordering::SeqCst) > 0); - } -} - /// A holder for potential task returned from the Scheduler. ExecutionTask and ValidationTask /// each contain a version of transaction that must be executed or validated, respectively. /// NoTask holds no task (similar None if we wrapped tasks in Option), and Done implies that /// there are no more tasks and the scheduler is done. -pub enum SchedulerTask<'a> { - ExecutionTask(Version, Option, TaskGuard<'a>), - ValidationTask(Version, TaskGuard<'a>), +#[derive(Debug)] +pub enum SchedulerTask { + ExecutionTask(Version, Option), + ValidationTask(Version, Wave), NoTask, Done, } -/// All possible statuses for each transaction. Each status contains the latest incarnation number. +/////////////////////////////// Explanation for ExecutionStatus /////////////////////////////// +/// All possible execution status for each transaction. In the explanation below, we abbreviate +/// 'execution status' as 'status'. Each status contains the latest incarnation number, +/// where incarnation = i means it is the i-th execution instance of the transaction. /// /// 'ReadyToExecute' means that the corresponding incarnation should be executed and the scheduler /// must eventually create a corresponding execution task. The scheduler ensures that exactly one @@ -75,35 +66,104 @@ pub enum SchedulerTask<'a> { /// | /// | finish_execution /// ↓ -/// Executed(i) (pending for (re)validations) +/// Executed(i) (pending for (re)validations) ---------------------------> Committed(i) /// | /// | try_abort (abort successfully) /// ↓ finish_abort /// Aborting(i) ---------------------------------------------------------> Ready(i+1) /// #[derive(Debug)] -enum TransactionStatus { +enum ExecutionStatus { ReadyToExecute(Incarnation, Option), Executing(Incarnation), Suspended(Incarnation, DependencyCondvar), + Committed(Incarnation), Executed(Incarnation), Aborting(Incarnation), } -impl PartialEq for TransactionStatus { +impl PartialEq for ExecutionStatus { fn eq(&self, other: &Self) -> bool { - use TransactionStatus::*; + use ExecutionStatus::*; match (self, other) { (&ReadyToExecute(ref a, _), &ReadyToExecute(ref b, _)) | (&Executing(ref a), &Executing(ref b)) | (&Suspended(ref a, _), &Suspended(ref b, _)) | (&Executed(ref a), &Executed(ref b)) + | (&Committed(ref a), &Committed(ref b)) | (&Aborting(ref a), &Aborting(ref b)) => a == b, _ => false, } } } +/////////////////////////////// Explanation for ValidationStatus /////////////////////////////// +/// All possible validation status for each transaction. In the explanation below, we abbreviate +/// 'validation status' as 'status'. Each status contains three wave numbers, each with different +/// meanings, but in general the concept of 'wave' keeps track of the version number of the validation. +/// +/// 'max_triggered_wave' records the maximum wave that was triggered at the transaction index, and +/// will be incremented every time when the validation_idx is decreased. Initialized as 0. +/// +/// 'maybe_max_validated_wave' records the maximum wave among successful validations of the corresponding +/// transaction, will be incremented upon successful validation (finish_validation). Initialized as None. +/// +/// 'required_wave' in addition records the wave that must be successfully validated in order +/// for the transaction to be committed, required to handle the case of the optimization in +/// finish_execution when only the transaction itself is validated (if last incarnation +/// didn't write outside of the previous write-set). Initilized as 0. +/// +/// Other than ValidationStatus, the 'wave' information is also recorded in 'validation_idx' and 'commit_state'. +/// Below is the description of the wave meanings and how they are updated. More details can be +/// found in the definition of 'validation_idx' and 'commit_state'. +/// +/// In 'validation_idx', the first 32 bits identifies a validation wave while the last 32 bits +/// contain an index that tracks the minimum of all transaction indices that require validation. +/// The wave is incremented whenever the validation_idx is reduced due to transactions requiring +/// validation, in particular, after aborts and executions that write outside of the write set of +/// the same transaction's previous incarnation. +/// +/// In 'commit_state', the first element records the next transaction to commit, and the +/// second element records the lower bound on the wave of a validation that must be successful +/// in order to commit the next transaction. The wave is updated in try_commit, upon seeing an +/// executed txn with higher max_triggered_wave. Note that the wave is *not* updated with the +/// required_wave of the txn that is being committed. +/// +/// +/////////////////////////////// Algorithm Description for Updating Waves /////////////////////////////// +/// In the following, 'update' means taking the maximum. +/// (1) Upon decreasing validation_idx, increment validation_idx.wave and update txn's +/// max_triggered_wave <- validation_idx.wave; +/// (2) Upon finishing execution of txn that is below validation_idx, update txn's +/// required_wave <- validation_idx.wave; (otherwise, the last triggered wave is below and will validate). +/// (3) Upon validating a txn successfully, update txn's maybe_max_validated_wave <- validation_idx.wave; +/// (4) Upon trying to commit an executed txn, update commit_state.wave <- txn's max_triggered_wave. +/// (5) If txn's maybe_max_validated_wave >= max(commit_state.wave, txn's required_wave), can commit the txn. +/// +/// Remark: commit_state.wave is updated only with max_triggered_wave but not required_wave. This is +/// because max_triggered_wave implies that this wave of validations was required for all higher transactions +/// (and is set as a part of decrease_validation_idx), while required_wave is set for the transaction only +/// (when a validation task is returned to the caller). Moreover, the code is structured in a way that +/// decrease_validation_idx is always called for txn_idx + 1 (e.g. when aborting, there is no need to validate +/// the transaction before re-execution, and in finish_execution, even if there is a need to validate txn_idx, +/// it is returned to the caller directly, which is done so as an optimization and also for uniformity). +#[derive(Debug)] +struct ValidationStatus { + max_triggered_wave: Wave, + required_wave: Wave, + maybe_max_validated_wave: Option, +} + +impl ValidationStatus { + pub fn new() -> Self { + ValidationStatus { + max_triggered_wave: 0, + required_wave: 0, + maybe_max_validated_wave: None, + } + } +} + pub struct Scheduler { /// Number of txns to execute, immutable. num_txns: usize, @@ -114,19 +174,21 @@ pub struct Scheduler { /// concurrent ordered set. It is reduced as necessary when transactions become ready to be /// executed, in particular, when execution finishes and dependencies are resolved. execution_idx: AtomicUsize, - /// A shared index that tracks the minimum of all transaction indices that require validation. - /// The threads increment the index and attempt to create a validation task for the corresponding - /// transaction, if the status of the txn is 'Executed'. This implements a counting-based - /// concurrent ordered set. It is reduced as necessary when transactions require validation, - /// in particular, after aborts and executions that write outside of the write set of the - /// same transaction's previous incarnation. - validation_idx: AtomicUsize, - /// The the number of times execution_idx and validation_idx are decreased. - decrease_cnt: AtomicUsize, - - /// Number of tasks used to track when transactions can be committed, incremented / decremented - /// as new validation or execution tasks are created and completed. - num_active_tasks: AtomicUsize, + /// The first 32 bits identifies a validation wave while the last 32 bits contain an index + /// that tracks the minimum of all transaction indices that require validation. + /// The threads increment this index and attempt to create a validation task for the + /// corresponding transaction (if the status of the txn is 'Executed'), associated with the + /// observed wave in the first 32 bits. Each validation wave represents the sequence of + /// validations that must happen due to the fixed serialization order of transactions. + /// The index is reduced as necessary when transactions require validation, in particular, + /// after aborts and executions that write outside of the write set of the same transaction's + /// previous incarnation. This also creates a new wave of validations, identified by the + /// monotonically increasing index stored in the first 32 bits. + validation_idx: AtomicU64, + /// Next transaction to commit, and sweeping lower bound on the wave of a validation that must + /// be successful in order to commit the next transaction. + commit_state: Mutex<(TxnIndex, Wave)>, + /// Shared marker that is set when a thread detects that all txns can be committed. done_marker: AtomicBool, @@ -134,7 +196,7 @@ pub struct Scheduler { /// should be re-executed once transaction i's next incarnation finishes. txn_dependency: Vec>>>, /// An index i maps to the most up-to-date status of transaction i. - txn_status: Vec>>, + txn_status: Vec, RwLock)>>, } /// Public Interfaces for the Scheduler @@ -143,22 +205,69 @@ impl Scheduler { Self { num_txns, execution_idx: AtomicUsize::new(0), - validation_idx: AtomicUsize::new(0), - decrease_cnt: AtomicUsize::new(0), - num_active_tasks: AtomicUsize::new(0), + validation_idx: AtomicU64::new(0), + commit_state: Mutex::new((0, 0)), done_marker: AtomicBool::new(false), txn_dependency: (0..num_txns) .map(|_| CachePadded::new(Mutex::new(Vec::new()))) .collect(), txn_status: (0..num_txns) - .map(|_| CachePadded::new(Mutex::new(TransactionStatus::ReadyToExecute(0, None)))) + .map(|_| { + CachePadded::new(( + RwLock::new(ExecutionStatus::ReadyToExecute(0, None)), + RwLock::new(ValidationStatus::new()), + )) + }) .collect(), } } - /// Return the number of transactions to be executed from the block. - pub fn num_txn_to_execute(&self) -> usize { - self.num_txns + /// If successful, returns Some(TxnIndex), the index of committed transaction. + /// The current implementation has one dedicated thread to try_commit. + /// Should not be called after the last transaction is committed. + pub fn try_commit(&self) -> Option { + let mut commit_state_mutex = self.commit_state.lock(); + let commit_state = commit_state_mutex.deref_mut(); + let (commit_idx, commit_wave) = (&mut commit_state.0, &mut commit_state.1); + + if let Some(validation_status) = self.txn_status[*commit_idx].1.try_read() { + // Acquired the validation status read lock. + if let Some(status) = self.txn_status[*commit_idx].0.try_upgradable_read() { + // Acquired the execution status read lock, which can be upgrade to write lock if necessary. + if let ExecutionStatus::Executed(incarnation) = *status { + // Status is executed and we are holding the lock. + + // Note we update the wave inside commit_state only with max_triggered_wave, + // since max_triggered_wave records the new wave when validation index is + // decreased thus affecting all later txns as well, + // while required_wave only records the new wave for one single txn. + *commit_wave = max(*commit_wave, validation_status.max_triggered_wave); + if let Some(validated_wave) = validation_status.maybe_max_validated_wave { + if validated_wave >= max(*commit_wave, validation_status.required_wave) { + let mut status_write = RwLockUpgradableReadGuard::upgrade(status); + // Upgrade the execution status read lock to write lock. + // Can commit. + *status_write = ExecutionStatus::Committed(incarnation); + + *commit_idx += 1; + if *commit_idx == self.num_txns { + // All txns have been committed, the parallel execution can finish. + self.done_marker.store(true, Ordering::SeqCst); + } + return Some(*commit_idx - 1); + } + } + } + } + } + None + } + + #[cfg(test)] + /// Return the TxnIndex and Wave of current commit index + pub fn commit_state(&self) -> (usize, u32) { + let commit_state = self.commit_state.lock(); + (commit_state.0, commit_state.1) } /// Try to abort version = (txn_idx, incarnation), called upon validation failure. @@ -167,11 +276,14 @@ impl Scheduler { /// returns false. Since incarnation numbers never decrease, this also ensures /// that the same version may not successfully abort more than once. pub fn try_abort(&self, txn_idx: TxnIndex, incarnation: Incarnation) -> bool { - // lock the status. - let mut status = self.txn_status[txn_idx].lock(); - - if *status == TransactionStatus::Executed(incarnation) { - *status = TransactionStatus::Aborting(incarnation); + // lock the execution status. + // Note: we could upgradable read, then upgrade and write. Similar for other places. + // However, it is likely an overkill (and overhead to actually upgrade), + // while unlikely there would be much contention on a specific index lock. + let mut status = self.txn_status[txn_idx].0.write(); + + if *status == ExecutionStatus::Executed(incarnation) { + *status = ExecutionStatus::Aborting(incarnation); true } else { false @@ -179,24 +291,47 @@ impl Scheduler { } /// Return the next task for the thread. - pub fn next_task(&self) -> SchedulerTask { + pub fn next_task(&self, committing: bool) -> SchedulerTask { loop { if self.done() { // No more tasks. return SchedulerTask::Done; } - let idx_to_validate = self.validation_idx.load(Ordering::SeqCst); - let idx_to_execute = self.execution_idx.load(Ordering::SeqCst); + let (idx_to_validate, wave) = + Self::unpack_validation_idx(self.validation_idx.load(Ordering::Acquire)); + let idx_to_execute = self.execution_idx.load(Ordering::Acquire); + + let prefer_validate = idx_to_validate < min(idx_to_execute, self.num_txns) + && !self.never_executed(idx_to_validate); + + if !prefer_validate && idx_to_execute >= self.num_txns { + return if self.done() { + // Check again to avoid commit delay due to a race. + SchedulerTask::Done + } else { + if !committing { + // Avoid pointlessly spinning, and give priority to other threads + // that may be working to finish the remaining tasks. + // We don't want to hint on the thread that is committing + // because it may have work to do (to commit) even if there + // is no more conventional (validation and execution tasks) work. + hint::spin_loop(); + } + SchedulerTask::NoTask + }; + } - if idx_to_validate < idx_to_execute { - if let Some((version_to_validate, guard)) = self.try_validate_next_version() { - return SchedulerTask::ValidationTask(version_to_validate, guard); + if prefer_validate { + if let Some((version_to_validate, wave)) = + self.try_validate_next_version(idx_to_validate, wave) + { + return SchedulerTask::ValidationTask(version_to_validate, wave); } - } else if let Some((version_to_execute, maybe_condvar, guard)) = + } else if let Some((version_to_execute, maybe_condvar)) = self.try_execute_next_version() { - return SchedulerTask::ExecutionTask(version_to_execute, maybe_condvar, guard); + return SchedulerTask::ExecutionTask(version_to_execute, maybe_condvar); } } } @@ -220,40 +355,54 @@ impl Scheduler { let mut stored_deps = self.txn_dependency[dep_txn_idx].lock(); - { - if self.is_executed(dep_txn_idx).is_some() { - // Current status of dep_txn_idx is 'executed', so the dependency got resolved. - // To avoid zombie dependency (and losing liveness), must return here and - // not add a (stale) dependency. + if self.is_executed(dep_txn_idx, true).is_some() { + // Current status of dep_txn_idx is 'executed', so the dependency got resolved. + // To avoid zombie dependency (and losing liveness), must return here and + // not add a (stale) dependency. - // Note: acquires (a different, status) mutex, while holding (dependency) mutex. - // Only place in scheduler where a thread may hold >1 mutexes, hence, such - // acquisitions always happens in the same order (this function), may not deadlock. + // Note: acquires (a different, status) mutex, while holding (dependency) mutex. + // Only place in scheduler where a thread may hold >1 mutexes, hence, such + // acquisitions always happens in the same order (this function), may not deadlock. - return None; - } + return None; + } - self.suspend(txn_idx, dep_condvar.clone()); + self.suspend(txn_idx, dep_condvar.clone()); - // Safe to add dependency here (still holding the lock) - finish_execution of txn - // dep_txn_idx is guaranteed to acquire the same lock later and clear the dependency. - stored_deps.push(txn_idx); - } + // Safe to add dependency here (still holding the lock) - finish_execution of txn + // dep_txn_idx is guaranteed to acquire the same lock later and clear the dependency. + stored_deps.push(txn_idx); Some(dep_condvar) } + pub fn finish_validation(&self, txn_idx: TxnIndex, wave: Wave) { + let mut validation_status = self.txn_status[txn_idx].1.write(); + validation_status.maybe_max_validated_wave = Some( + validation_status + .maybe_max_validated_wave + .map_or(wave, |prev_wave| max(prev_wave, wave)), + ); + } + /// After txn is executed, schedule its dependencies for re-execution. /// If revalidate_suffix is true, decrease validation_idx to schedule all higher transactions /// for (re-)validation. Otherwise, in some cases (if validation_idx not already lower), /// return a validation task of the transaction to the caller (otherwise NoTask). - pub fn finish_execution<'a>( + pub fn finish_execution( &self, txn_idx: TxnIndex, incarnation: Incarnation, revalidate_suffix: bool, - guard: TaskGuard<'a>, - ) -> SchedulerTask<'a> { + ) -> SchedulerTask { + // Note: It is preferable to hold the validation lock throughout the finish_execution, + // in particular before updating execution status. The point was that we don't want + // any validation to come before the validation status is correspondingly updated. + // It may be possible to make work more granularly, but shouldn't make performance + // difference and like this correctness argument is much easier to see, in fact also + // the reason why we grab write lock directly, and never release it during the whole function. + // So even validation status readers have to wait if they somehow end up at the same index. + let mut validation_status = self.txn_status[txn_idx].1.write(); self.set_executed_status(txn_idx, incarnation); let txn_deps: Vec = { @@ -276,22 +425,27 @@ impl Scheduler { if let Some(execution_target_idx) = min_dep { // Decrease the execution index as necessary to ensure resolved dependencies // get a chance to be re-executed. - self.decrease_execution_idx(execution_target_idx); + self.execution_idx + .fetch_min(execution_target_idx, Ordering::SeqCst); } + let (cur_val_idx, mut cur_wave) = + Self::unpack_validation_idx(self.validation_idx.load(Ordering::Acquire)); + // If validation_idx is already lower than txn_idx, all required transactions will be // considered for validation, and there is nothing to do. - if self.validation_idx.load(Ordering::SeqCst) > txn_idx { + if cur_val_idx > txn_idx { if revalidate_suffix { // The transaction execution required revalidating all higher txns (not // only itself), currently happens when incarnation writes to a new path // (w.r.t. the write-set of its previous completed incarnation). - self.decrease_validation_idx(txn_idx); - } else { - // Only transaction txn_idx requires validation. Return validation task - // back to the caller. No need to change active tasks (-1 +1= 0) - return SchedulerTask::ValidationTask((txn_idx, incarnation), guard); + if let Some(wave) = self.decrease_validation_idx(txn_idx + 1) { + cur_wave = wave; + }; } + // Update the minimum wave this txn needs to pass. + validation_status.required_wave = cur_wave; + return SchedulerTask::ValidationTask((txn_idx, incarnation), cur_wave); } SchedulerTask::NoTask @@ -299,20 +453,30 @@ impl Scheduler { /// Finalize a validation task of version (txn_idx, incarnation). In some cases, /// may return a re-execution task back to the caller (otherwise, NoTask). - pub fn finish_abort<'a>( - &self, - txn_idx: TxnIndex, - incarnation: Incarnation, - guard: TaskGuard<'a>, - ) -> SchedulerTask<'a> { - self.set_aborted_status(txn_idx, incarnation); - - // Schedule strictly higher txns for validation - // (txn_idx needs to be re-executed first). - self.decrease_validation_idx(txn_idx + 1); + pub fn finish_abort(&self, txn_idx: TxnIndex, incarnation: Incarnation) -> SchedulerTask { + { + // acquire exclusive lock on the validation status of txn_idx, and hold the lock + // while calling decrease_validation_idx below. Otherwise, this thread might get + // suspended after setting aborted ( = ready) status, and other threads might finish + // re-executing, then commit txn_idx, and potentially commit txn_idx + 1 before + // decrease_validation_idx would be able to set max_triggered_wave. + // + // Also, as a convention, we always acquire validation status lock before execution + // status lock, as we have to have a consistent order and this order is easier to + // provide correctness between finish_execution & try_commit. + let _validation_status = self.txn_status[txn_idx].1.write(); + + self.set_aborted_status(txn_idx, incarnation); + + // Schedule higher txns for validation, skipping txn_idx itself (needs to be + // re-executed first). + self.decrease_validation_idx(txn_idx + 1); + + // can release the lock early. + } // txn_idx must be re-executed, and if execution_idx is lower, it will be. - if self.execution_idx.load(Ordering::SeqCst) > txn_idx { + if self.execution_idx.load(Ordering::Acquire) > txn_idx { // Optimization: execution_idx is higher than txn_idx, but decreasing it may // lead to wasted work for all indices between txn_idx and execution_idx. // Instead, attempt to create a new incarnation and return the corresponding @@ -320,11 +484,7 @@ impl Scheduler { // nothing to do, as another thread must have succeeded to incarnate and // obtain the task for re-execution. if let Some((new_incarnation, maybe_condvar)) = self.try_incarnate(txn_idx) { - return SchedulerTask::ExecutionTask( - (txn_idx, new_incarnation), - maybe_condvar, - guard, - ); + return SchedulerTask::ExecutionTask((txn_idx, new_incarnation), maybe_condvar); } } @@ -334,17 +494,47 @@ impl Scheduler { /// Public functions of the Scheduler impl Scheduler { - /// Decreases the validation index, increases the decrease counter if it actually decreased. - fn decrease_validation_idx(&self, target_idx: TxnIndex) { - if self.validation_idx.fetch_min(target_idx, Ordering::SeqCst) > target_idx { - self.decrease_cnt.fetch_add(1, Ordering::SeqCst); - } + fn unpack_validation_idx(validation_idx: u64) -> (TxnIndex, Wave) { + ( + (validation_idx & TXN_IDX_MASK) as TxnIndex, + (validation_idx >> 32) as Wave, + ) } - /// Decreases the execution index, increases the decrease counter if it actually decreased. - fn decrease_execution_idx(&self, target_idx: TxnIndex) { - if self.execution_idx.fetch_min(target_idx, Ordering::SeqCst) > target_idx { - self.decrease_cnt.fetch_add(1, Ordering::SeqCst); + /// Decreases the validation index, adjusting the wave and validation status as needed. + fn decrease_validation_idx(&self, target_idx: TxnIndex) -> Option { + // We only call with txn_idx + 1, so it can equal num_txns, but not be strictly larger. + debug_assert!(target_idx <= self.num_txns); + if target_idx >= self.num_txns { + return None; + } + + if let Ok(prev_val_idx) = + self.validation_idx + .fetch_update(Ordering::Acquire, Ordering::SeqCst, |val_idx| { + let (txn_idx, wave) = Self::unpack_validation_idx(val_idx); + if txn_idx > target_idx { + let mut validation_status = self.txn_status[target_idx].1.write(); + // Update the minimum wave all the suffix txn needs to pass. + // We set it to max for safety (to avoid overwriting with lower values + // by a slower thread), but currently this isn't strictly required + // as all callers of decrease_validation_idx hold a write lock on the + // previous transaction's validation status. + validation_status.max_triggered_wave = + max(validation_status.max_triggered_wave, wave + 1); + + // Pack into validation index. + Some((target_idx as u64) | ((wave as u64 + 1) << 32)) + } else { + None + } + }) + { + let (_, wave) = Self::unpack_validation_idx(prev_val_idx); + // Note that 'wave' is the previous wave value, and we must update it to 'wave + 1'. + Some(wave + 1) + } else { + None } } @@ -358,10 +548,13 @@ impl Scheduler { return None; } - let mut status = self.txn_status[txn_idx].lock(); - if let TransactionStatus::ReadyToExecute(incarnation, maybe_condvar) = &*status { + // Note: we could upgradable read, then upgrade and write. Similar for other places. + // However, it is likely an overkill (and overhead to actually upgrade), + // while unlikely there would be much contention on a specific index lock. + let mut status = self.txn_status[txn_idx].0.write(); + if let ExecutionStatus::ReadyToExecute(incarnation, maybe_condvar) = &*status { let ret = (*incarnation, maybe_condvar.clone()); - *status = TransactionStatus::Executing(*incarnation); + *status = ExecutionStatus::Executing(*incarnation); Some(ret) } else { None @@ -369,47 +562,81 @@ impl Scheduler { } /// If the status of transaction is Executed(incarnation), returns Some(incarnation), - /// otherwise returns None. Useful to determine when a transaction can be validated, - /// and to avoid a race in dependency resolution. - fn is_executed(&self, txn_idx: TxnIndex) -> Option { - if txn_idx >= self.txn_status.len() { - return None; + /// Useful to determine when a transaction can be validated, and to avoid a race in + /// dependency resolution. + /// If include_committed is true (which is when calling from wait_for_dependency), + /// then committed transaction is also considered executed (for dependency resolution + /// purposes). If include_committed is false (which is when calling from + /// try_validate_next_version), then we are checking if a transaction may be validated, + /// and a committed (in between) txn does not need to be scheduled for validation - + /// so can return None. + fn is_executed(&self, txn_idx: TxnIndex, include_committed: bool) -> Option { + let status = self.txn_status[txn_idx].0.read(); + match *status { + ExecutionStatus::Executed(incarnation) => Some(incarnation), + ExecutionStatus::Committed(incarnation) => { + if include_committed { + // Committed txns are also considered executed for dependency resolution purposes. + Some(incarnation) + } else { + // Committed txns do not need to be scheduled for validation in try_validate_next_version. + None + } + } + _ => None, } + } - let status = self.txn_status[txn_idx].lock(); - if let TransactionStatus::Executed(incarnation) = *status { - Some(incarnation) - } else { - None - } + /// Returns true iff no incarnation (even the 0-th one) has set the executed status, i.e. + /// iff the execution status is READY_TO_EXECUTE/EXECUTING/SUSPENDED for incarnation 0. + fn never_executed(&self, txn_idx: TxnIndex) -> bool { + let status = self.txn_status[txn_idx].0.read(); + matches!( + *status, + ExecutionStatus::ReadyToExecute(0, _) + | ExecutionStatus::Executing(0) + | ExecutionStatus::Suspended(0, _) + ) } /// Grab an index to try and validate next (by fetch-and-incrementing validation_idx). /// - If the index is out of bounds, return None (and invoke a check of whethre /// all txns can be committed). /// - If the transaction is ready for validation (EXECUTED state), return the version - /// to the caller together with a guard to be used for the corresponding ValidationTask. + /// to the caller. /// - Otherwise, return None. - fn try_validate_next_version(&self) -> Option<(Version, TaskGuard)> { - let idx_to_validate = self.validation_idx.load(Ordering::SeqCst); - - if idx_to_validate >= self.num_txns { - if !self.check_done() { - // Avoid pointlessly spinning, and give priority to other threads that may - // be working to finish the remaining tasks. - hint::spin_loop(); - } - return None; + fn try_validate_next_version( + &self, + idx_to_validate: TxnIndex, + wave: Wave, + ) -> Option<(Version, Wave)> { + // We do compare-and-swap here instead of fetch-and-increment as for execution index + // because we would like to not validate transactions when lower indices are in the + // 'never_executed' state (to avoid unnecessarily reducing validation index and creating + // redundant validation tasks). This is checked in the caller (in 'next_task' function), + // but if we used fetch-and-increment, two threads can arrive in a cloned state and + // both increment, effectively skipping over the 'never_executed' transaction index. + let validation_idx = (idx_to_validate as u64) | ((wave as u64) << 32); + let new_validation_idx = ((idx_to_validate + 1) as u64) | ((wave as u64) << 32); + if self + .validation_idx + .compare_exchange( + validation_idx, + new_validation_idx, + Ordering::Acquire, + Ordering::SeqCst, + ) + .is_ok() + { + // Successfully claimed idx_to_validate to attempt validation. + // If incarnation was last executed, and thus ready for validation, + // return version and wave for validation task, otherwise None. + return self + .is_executed(idx_to_validate, false) + .map(|incarnation| ((idx_to_validate, incarnation), wave)); } - // Must create guard before incremeting validation_idx. - let guard = TaskGuard::new(&self.num_active_tasks); - let idx_to_validate = self.validation_idx.fetch_add(1, Ordering::SeqCst); - - // If incarnation was last executed, and thus ready for validation, - // return version and guard for validation task, otherwise None. - self.is_executed(idx_to_validate) - .map(|incarnation| ((idx_to_validate, incarnation), guard)) + None } /// Grab an index to try and execute next (by fetch-and-incrementing execution_idx). @@ -417,41 +644,28 @@ impl Scheduler { /// all txns can be committed). /// - If the transaction is ready for execution (ReadyToExecute state), attempt /// to create the next incarnation (should happen exactly once), and if successful, - /// return the version to the caller together with a guard to be used for the - /// corresponding ExecutionTask. + /// return the version to the caller for the corresponding ExecutionTask. /// - Otherwise, return None. - fn try_execute_next_version(&self) -> Option<(Version, Option, TaskGuard)> { - let idx_to_execute = self.execution_idx.load(Ordering::SeqCst); + fn try_execute_next_version(&self) -> Option<(Version, Option)> { + let idx_to_execute = self.execution_idx.fetch_add(1, Ordering::SeqCst); if idx_to_execute >= self.num_txns { - if !self.check_done() { - // Avoid pointlessly spinning, and give priority to other threads that may - // be working to finish the remaining tasks. - hint::spin_loop(); - } return None; } - // Must create a guard before incrementing execution_idx. - let guard = TaskGuard::new(&self.num_active_tasks); - - let idx_to_execute = self.execution_idx.fetch_add(1, Ordering::SeqCst); - // If successfully incarnated (changed status from ready to executing), - // return version and guard for execution task, otherwise None. + // return version for execution task, otherwise None. self.try_incarnate(idx_to_execute) - .map(|(incarnation, maybe_condvar)| { - ((idx_to_execute, incarnation), maybe_condvar, guard) - }) + .map(|(incarnation, maybe_condvar)| ((idx_to_execute, incarnation), maybe_condvar)) } /// Put a transaction in a suspended state, with a condition variable that can be /// used to wake it up after the dependency is resolved. fn suspend(&self, txn_idx: TxnIndex, dep_condvar: DependencyCondvar) { - let mut status = self.txn_status[txn_idx].lock(); + let mut status = self.txn_status[txn_idx].0.write(); - if let TransactionStatus::Executing(incarnation) = *status { - *status = TransactionStatus::Suspended(incarnation, dep_condvar); + if let ExecutionStatus::Executing(incarnation) = *status { + *status = ExecutionStatus::Suspended(incarnation, dep_condvar); } else { unreachable!(); } @@ -461,9 +675,10 @@ impl Scheduler { /// incremented incarnation number. /// The caller must ensure that the transaction is in the Suspended state. fn resume(&self, txn_idx: TxnIndex) { - let mut status = self.txn_status[txn_idx].lock(); - if let TransactionStatus::Suspended(incarnation, dep_condvar) = &*status { - *status = TransactionStatus::ReadyToExecute(*incarnation, Some(dep_condvar.clone())); + let mut status = self.txn_status[txn_idx].0.write(); + + if let ExecutionStatus::Suspended(incarnation, dep_condvar) = &*status { + *status = ExecutionStatus::ReadyToExecute(*incarnation, Some(dep_condvar.clone())); } else { unreachable!(); } @@ -471,58 +686,26 @@ impl Scheduler { /// Set status of the transaction to Executed(incarnation). fn set_executed_status(&self, txn_idx: TxnIndex, incarnation: Incarnation) { - let mut status = self.txn_status[txn_idx].lock(); + let mut status = self.txn_status[txn_idx].0.write(); // Only makes sense when the current status is 'Executing'. - debug_assert!(*status == TransactionStatus::Executing(incarnation)); + debug_assert!(*status == ExecutionStatus::Executing(incarnation)); - *status = TransactionStatus::Executed(incarnation); + *status = ExecutionStatus::Executed(incarnation); } /// After a successful abort, mark the transaction as ready for re-execution with /// an incremented incarnation number. fn set_aborted_status(&self, txn_idx: TxnIndex, incarnation: Incarnation) { - let mut status = self.txn_status[txn_idx].lock(); + let mut status = self.txn_status[txn_idx].0.write(); // Only makes sense when the current status is 'Aborting'. - debug_assert!(*status == TransactionStatus::Aborting(incarnation)); - - *status = TransactionStatus::ReadyToExecute(incarnation + 1, None); - } - - /// A lazy, check of whether the scheduler execution is completed. - /// Updates the 'done_marker' so other threads can know by calling done() function below. - /// - /// 1. After the STM execution has completed: - /// validation_idx >= num_txn, execution_idx >= num_txn, num_active_tasks == 0, - /// and decrease_cnt does not change - so it will be successfully detected. - /// 2. If done_marker is set, all of these must hold at the same time, implying completion. - /// Proof: O.w. one of the indices must decrease from when it is read to be >= num_txns - /// to when num_active_tasks is read to be 0, but decreasing thread is performing an active task, - /// so it must first perform the next instruction in 'decrease_validation_idx' or - /// 'decrease_execution_idx' functions, which is to increment the decrease_cnt++. - /// Final check will then detect a change in decrease_cnt and not allow a false positive. - fn check_done(&self) -> bool { - let observed_cnt = self.decrease_cnt.load(Ordering::SeqCst); - - let val_idx = self.validation_idx.load(Ordering::SeqCst); - let exec_idx = self.execution_idx.load(Ordering::SeqCst); - let num_tasks = self.num_active_tasks.load(Ordering::SeqCst); - if min(exec_idx, val_idx) < self.num_txns || num_tasks > 0 { - // There is work remaining. - return false; - } + debug_assert!(*status == ExecutionStatus::Aborting(incarnation)); - // Re-read and make sure decrease_cnt hasn't changed. - if observed_cnt == self.decrease_cnt.load(Ordering::SeqCst) { - self.done_marker.store(true, Ordering::Release); - true - } else { - false - } + *status = ExecutionStatus::ReadyToExecute(incarnation + 1, None); } - /// Checks whether the done marker is set. The marker can only be set by 'check_done'. + /// Checks whether the done marker is set. The marker can only be set by 'try_commit'. fn done(&self) -> bool { self.done_marker.load(Ordering::Acquire) } diff --git a/vm/transaction-benchmarks/src/transactions.rs b/vm/transaction-benchmarks/src/transactions.rs index 4666e65d1a..a4c153733e 100644 --- a/vm/transaction-benchmarks/src/transactions.rs +++ b/vm/transaction-benchmarks/src/transactions.rs @@ -266,19 +266,19 @@ impl TransactionBenchState { transactions_len * 1000 / exec_t.as_millis() as usize } - /// Executes this state in a single block via parallel execution. - fn execute_parallel(self) { - // The output is ignored here since we're just testing transaction performance, not trying - // to assert correctness. - BlockStarcoinVM::execute_block( - self.transactions, - self.executor.get_state_view(), - num_cpus::get(), - None, - None, - ) - .expect("VM should not fail to start"); - } + /// Executes this state in a single block via parallel execution. + fn execute_parallel(self) { + // The output is ignored here since we're just testing transaction performance, not trying + // to assert correctness. + BlockStarcoinVM::execute_block( + self.transactions, + self.executor.get_state_view(), + num_cpus::get(), + None, + None, + ) + .expect("VM should not fail to start"); + } fn execute_blockstm_benchmark( self, @@ -308,4 +308,3 @@ fn universe_strategy( let balance = TXN_RESERVED * num_transactions as u64 * 5; AccountUniverseGen::strategy(num_accounts, balance..(balance + 1)) } - diff --git a/vm/types/src/write_set.rs b/vm/types/src/write_set.rs index e37993c855..465765d7ee 100644 --- a/vm/types/src/write_set.rs +++ b/vm/types/src/write_set.rs @@ -22,6 +22,24 @@ impl WriteOp { WriteOp::Value(_) => false, } } + + pub fn into_bytes(self) -> Option> { + use WriteOp::*; + match self { + Value(data) => Some(data), + Deletion => None, + } + } +} + +pub trait TransactionWrite { + fn extract_raw_bytes(&self) -> Option>; +} + +impl TransactionWrite for WriteOp { + fn extract_raw_bytes(&self) -> Option> { + self.clone().into_bytes() + } } impl std::fmt::Debug for WriteOp { From 0a53d0f3670a99ce207634609bea47fc5f4a8fa8 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Thu, 5 Oct 2023 19:50:04 +0800 Subject: [PATCH 54/89] update AccountNum --- scripts/benchmark_parallel.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/benchmark_parallel.sh b/scripts/benchmark_parallel.sh index 5248d1d977..19f3806c29 100755 --- a/scripts/benchmark_parallel.sh +++ b/scripts/benchmark_parallel.sh @@ -4,7 +4,7 @@ STARCOIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd .. && pwd)" TXN_NUMS=500000 -ACCOUNT_NUMS=1000000 +ACCOUNT_NUMS=10000 if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux @@ -39,4 +39,4 @@ IFS=',' power_of_two_str="${power_of_two_array[*]}" #echo "Power of two array: ${power_of_two_str[@]}" -eval RUST_LOG=info cargo run --release -p "starcoin-transaction-benchmarks" --features fuzzing -- --concurrency-level "24" --txn-nums "$TXN_NUMS" --account-nums="$ACCOUNT_NUMS" \ No newline at end of file +eval RUST_LOG=info cargo run --release -p "starcoin-transaction-benchmarks" --features fuzzing -- --concurrency-level "36" --txn-nums "$TXN_NUMS" --account-nums="$ACCOUNT_NUMS" \ No newline at end of file From cbeda3dbb2958165e05bad42fe24f7c152edb18a Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Thu, 5 Oct 2023 20:37:53 +0800 Subject: [PATCH 55/89] update AccountNum --- scripts/benchmark_parallel.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/benchmark_parallel.sh b/scripts/benchmark_parallel.sh index 19f3806c29..c21c1748a6 100755 --- a/scripts/benchmark_parallel.sh +++ b/scripts/benchmark_parallel.sh @@ -4,7 +4,7 @@ STARCOIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd .. && pwd)" TXN_NUMS=500000 -ACCOUNT_NUMS=10000 +ACCOUNT_NUMS=1000000 if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux From 76371c750bdcbb29f82e8e8706cdcaaca80506a2 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Thu, 5 Oct 2023 21:35:36 +0800 Subject: [PATCH 56/89] update AccountNum --- scripts/benchmark_parallel.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/benchmark_parallel.sh b/scripts/benchmark_parallel.sh index c21c1748a6..0384ba2549 100755 --- a/scripts/benchmark_parallel.sh +++ b/scripts/benchmark_parallel.sh @@ -4,7 +4,7 @@ STARCOIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd .. && pwd)" TXN_NUMS=500000 -ACCOUNT_NUMS=1000000 +ACCOUNT_NUMS=100000 if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux From f1ea1e6bc06ba123d78254061789caaa562a3396 Mon Sep 17 00:00:00 2001 From: welbon Date: Sun, 8 Oct 2023 13:05:07 +0800 Subject: [PATCH 57/89] commit for test --- scripts/benchmark_parallel.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/benchmark_parallel.sh b/scripts/benchmark_parallel.sh index 0384ba2549..0f36e69bae 100755 --- a/scripts/benchmark_parallel.sh +++ b/scripts/benchmark_parallel.sh @@ -39,4 +39,4 @@ IFS=',' power_of_two_str="${power_of_two_array[*]}" #echo "Power of two array: ${power_of_two_str[@]}" -eval RUST_LOG=info cargo run --release -p "starcoin-transaction-benchmarks" --features fuzzing -- --concurrency-level "36" --txn-nums "$TXN_NUMS" --account-nums="$ACCOUNT_NUMS" \ No newline at end of file +eval RUST_LOG=info cargo run --release -p "starcoin-transaction-benchmarks" --features fuzzing -- --concurrency-level "32" --txn-nums "$TXN_NUMS" --account-nums="$ACCOUNT_NUMS" \ No newline at end of file From b1ea59c4693e0ef8142c27e24c892d78ea07c0de Mon Sep 17 00:00:00 2001 From: welbon Date: Mon, 9 Oct 2023 14:35:14 +0800 Subject: [PATCH 58/89] commit for test --- scripts/benchmark_parallel.sh | 8 ++++---- vm/vm-runtime/src/starcoin_vm.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/benchmark_parallel.sh b/scripts/benchmark_parallel.sh index 0f36e69bae..ddc1c8fd71 100755 --- a/scripts/benchmark_parallel.sh +++ b/scripts/benchmark_parallel.sh @@ -3,8 +3,8 @@ #RUST_LOG=info cargo bench --features fuzzing -p 'starcoin-transaction-benchmarks' STARCOIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd .. && pwd)" -TXN_NUMS=500000 -ACCOUNT_NUMS=100000 +TXN_NUMS=5000,10000,50000,100000 +ACCOUNT_NUMS=10000 if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux @@ -26,7 +26,7 @@ else current_power=4 while (( current_power <= physical_cores )); do power_of_two_array+=($current_power) - current_power=$((current_power * 2)) + current_power=$((current_power << 1)) done if ! [[ " ${power_of_two_array[@]} " =~ " ${physical_cores} " ]]; then @@ -39,4 +39,4 @@ IFS=',' power_of_two_str="${power_of_two_array[*]}" #echo "Power of two array: ${power_of_two_str[@]}" -eval RUST_LOG=info cargo run --release -p "starcoin-transaction-benchmarks" --features fuzzing -- --concurrency-level "32" --txn-nums "$TXN_NUMS" --account-nums="$ACCOUNT_NUMS" \ No newline at end of file +eval RUST_LOG=info cargo run --release -p "starcoin-transaction-benchmarks" --features fuzzing -- --concurrency-level "$power_of_two_str" --txn-nums "$TXN_NUMS" --account-nums="$ACCOUNT_NUMS" \ No newline at end of file diff --git a/vm/vm-runtime/src/starcoin_vm.rs b/vm/vm-runtime/src/starcoin_vm.rs index 2c2d6c6097..8643de136d 100644 --- a/vm/vm-runtime/src/starcoin_vm.rs +++ b/vm/vm-runtime/src/starcoin_vm.rs @@ -1615,7 +1615,7 @@ impl VMAdapter for StarcoinVM { (vm_status, output, Some(sender)) } PreprocessedTransaction::BlockMetadata(block_meta) => { - println!("YSG BlockMetadata"); + // println!("YSG BlockMetadata"); let (vm_status, output) = match self.process_block_metadata(data_cache, block_meta.clone()) { Ok(output) => (VMStatus::Executed, output), From dc0dc2f63297c01d8260e22250b5d2145b7e2f73 Mon Sep 17 00:00:00 2001 From: welbon Date: Mon, 9 Oct 2023 16:34:46 +0800 Subject: [PATCH 59/89] commit for test --- scripts/benchmark_parallel.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/benchmark_parallel.sh b/scripts/benchmark_parallel.sh index ddc1c8fd71..37e64ae91f 100755 --- a/scripts/benchmark_parallel.sh +++ b/scripts/benchmark_parallel.sh @@ -4,7 +4,7 @@ STARCOIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd .. && pwd)" TXN_NUMS=5000,10000,50000,100000 -ACCOUNT_NUMS=10000 +ACCOUNT_NUMS=1000,10000,100000 if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux From 99a739e45fc4830606568e7262ef5c39882fdf19 Mon Sep 17 00:00:00 2001 From: welbon Date: Mon, 9 Oct 2023 16:36:27 +0800 Subject: [PATCH 60/89] commit for test --- scripts/benchmark_parallel.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/benchmark_parallel.sh b/scripts/benchmark_parallel.sh index 37e64ae91f..9cd20a7a4a 100755 --- a/scripts/benchmark_parallel.sh +++ b/scripts/benchmark_parallel.sh @@ -3,7 +3,7 @@ #RUST_LOG=info cargo bench --features fuzzing -p 'starcoin-transaction-benchmarks' STARCOIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd .. && pwd)" -TXN_NUMS=5000,10000,50000,100000 +TXN_NUMS=5000,10000,50000,100000,500000 ACCOUNT_NUMS=1000,10000,100000 if [[ "$OSTYPE" == "linux-gnu"* ]]; then From 5987954b0b3bd71a57fb683ad7c0f61d21048069 Mon Sep 17 00:00:00 2001 From: welbon Date: Wed, 11 Oct 2023 17:38:06 +0800 Subject: [PATCH 61/89] commit for test --- scripts/benchmark_parallel.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/benchmark_parallel.sh b/scripts/benchmark_parallel.sh index 9cd20a7a4a..a4400efef1 100755 --- a/scripts/benchmark_parallel.sh +++ b/scripts/benchmark_parallel.sh @@ -4,7 +4,7 @@ STARCOIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd .. && pwd)" TXN_NUMS=5000,10000,50000,100000,500000 -ACCOUNT_NUMS=1000,10000,100000 +ACCOUNT_NUMS=2,10,100,1000,5000,10000,50000,100000 if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux From c989de0c7a7d0c88cebe94a47ecbfe130760da7c Mon Sep 17 00:00:00 2001 From: welbon Date: Wed, 8 Nov 2023 18:33:44 +0800 Subject: [PATCH 62/89] test suit cherry pick --- Cargo.lock | 24 + Cargo.toml | 3 + .../src/iterator/iterator_test.rs | 2 +- vm/e2e-tests/src/versioning.rs | 6 +- vm/e2e-testsuite/Cargo.toml | 51 + vm/e2e-testsuite/src/lib.rs | 5 + vm/e2e-testsuite/src/tests/account_limits.rs | 732 +++++++ .../tests/account_universe/bad_transaction.rs | 37 + .../tests/account_universe/create_account.rs | 78 + .../src/tests/account_universe/mod.rs | 84 + .../tests/account_universe/peer_to_peer.rs | 56 + .../src/tests/account_universe/rotate_key.rs | 40 + vm/e2e-testsuite/src/tests/admin_script.rs | 188 ++ vm/e2e-testsuite/src/tests/create_account.rs | 49 + vm/e2e-testsuite/src/tests/crsn.rs | 298 +++ vm/e2e-testsuite/src/tests/data_store.rs | 373 ++++ .../src/tests/emergency_admin_script.rs | 267 +++ .../src/tests/execution_strategies.rs | 120 ++ vm/e2e-testsuite/src/tests/experimental.rs | 65 + .../src/tests/failed_transaction_tests.rs | 101 + vm/e2e-testsuite/src/tests/genesis.rs | 42 + .../src/tests/genesis_initializations.rs | 190 ++ vm/e2e-testsuite/src/tests/mint.rs | 202 ++ vm/e2e-testsuite/src/tests/mod.rs | 41 + .../src/tests/module_publishing.rs | 452 +++++ vm/e2e-testsuite/src/tests/multi_agent.rs | 249 +++ .../src/tests/on_chain_configs.rs | 228 +++ .../src/tests/parallel_execution.rs | 242 +++ vm/e2e-testsuite/src/tests/peer_to_peer.rs | 595 ++++++ vm/e2e-testsuite/src/tests/preburn_queue.rs | 340 ++++ vm/e2e-testsuite/src/tests/rotate_key.rs | 140 ++ .../src/tests/script_functions.rs | 186 ++ vm/e2e-testsuite/src/tests/scripts.rs | 426 +++++ .../src/tests/transaction_builder.rs | 1268 +++++++++++++ .../src/tests/transaction_fees.rs | 112 ++ .../src/tests/transaction_fuzzer.rs | 93 + .../src/tests/validator_set_management.rs | 434 +++++ vm/e2e-testsuite/src/tests/vasps.rs | 196 ++ vm/e2e-testsuite/src/tests/verify_txn.rs | 1686 +++++++++++++++++ vm/e2e-testsuite/src/tests/write_set.rs | 359 ++++ .../src/tests/writeset_builder.rs | 101 + vm/transaction-benchmarks/src/main.rs | 15 +- 42 files changed, 10169 insertions(+), 7 deletions(-) create mode 100644 vm/e2e-testsuite/Cargo.toml create mode 100644 vm/e2e-testsuite/src/lib.rs create mode 100644 vm/e2e-testsuite/src/tests/account_limits.rs create mode 100644 vm/e2e-testsuite/src/tests/account_universe/bad_transaction.rs create mode 100644 vm/e2e-testsuite/src/tests/account_universe/create_account.rs create mode 100644 vm/e2e-testsuite/src/tests/account_universe/mod.rs create mode 100644 vm/e2e-testsuite/src/tests/account_universe/peer_to_peer.rs create mode 100644 vm/e2e-testsuite/src/tests/account_universe/rotate_key.rs create mode 100644 vm/e2e-testsuite/src/tests/admin_script.rs create mode 100644 vm/e2e-testsuite/src/tests/create_account.rs create mode 100644 vm/e2e-testsuite/src/tests/crsn.rs create mode 100644 vm/e2e-testsuite/src/tests/data_store.rs create mode 100644 vm/e2e-testsuite/src/tests/emergency_admin_script.rs create mode 100644 vm/e2e-testsuite/src/tests/execution_strategies.rs create mode 100644 vm/e2e-testsuite/src/tests/experimental.rs create mode 100644 vm/e2e-testsuite/src/tests/failed_transaction_tests.rs create mode 100644 vm/e2e-testsuite/src/tests/genesis.rs create mode 100644 vm/e2e-testsuite/src/tests/genesis_initializations.rs create mode 100644 vm/e2e-testsuite/src/tests/mint.rs create mode 100644 vm/e2e-testsuite/src/tests/mod.rs create mode 100644 vm/e2e-testsuite/src/tests/module_publishing.rs create mode 100644 vm/e2e-testsuite/src/tests/multi_agent.rs create mode 100644 vm/e2e-testsuite/src/tests/on_chain_configs.rs create mode 100644 vm/e2e-testsuite/src/tests/parallel_execution.rs create mode 100644 vm/e2e-testsuite/src/tests/peer_to_peer.rs create mode 100644 vm/e2e-testsuite/src/tests/preburn_queue.rs create mode 100644 vm/e2e-testsuite/src/tests/rotate_key.rs create mode 100644 vm/e2e-testsuite/src/tests/script_functions.rs create mode 100644 vm/e2e-testsuite/src/tests/scripts.rs create mode 100644 vm/e2e-testsuite/src/tests/transaction_builder.rs create mode 100644 vm/e2e-testsuite/src/tests/transaction_fees.rs create mode 100644 vm/e2e-testsuite/src/tests/transaction_fuzzer.rs create mode 100644 vm/e2e-testsuite/src/tests/validator_set_management.rs create mode 100644 vm/e2e-testsuite/src/tests/vasps.rs create mode 100644 vm/e2e-testsuite/src/tests/verify_txn.rs create mode 100644 vm/e2e-testsuite/src/tests/write_set.rs create mode 100644 vm/e2e-testsuite/src/tests/writeset_builder.rs diff --git a/Cargo.lock b/Cargo.lock index 683a13a254..ddc01775d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9864,6 +9864,30 @@ dependencies = [ "test-helper", ] +[[package]] +name = "starcoin-language-e2e-testsuite" +version = "1.13.7" +dependencies = [ + "bcs", + "hex", + "move-binary-format", + "move-bytecode-verifier", + "move-core-types", + "move-ir-compiler", + "move-vm-runtime", + "move-vm-types", + "proptest", + "read-write-set", + "serde_json", + "starcoin-crypto", + "starcoin-language-e2e-tests", + "starcoin-logger", + "starcoin-transaction-builder", + "starcoin-types", + "starcoin-vm-runtime", + "starcoin-vm-types", +] + [[package]] name = "starcoin-logger" version = "1.13.7" diff --git a/Cargo.toml b/Cargo.toml index d4f6ecf1de..a70476b26d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -90,6 +90,7 @@ members = [ "vm/block-executor", "vm/transaction-benchmarks", "vm/e2e-tests", + "vm/e2e-testsuite", "vm/proptest-helpers", "abi/types", "abi/decoder", @@ -358,6 +359,7 @@ move-vm-runtime = { git = "https://github.com/starcoinorg/move", rev = "0b3686b4 move-vm-types = { git = "https://github.com/starcoinorg/move", rev = "0b3686b4edcd37fd0c61c1aa26859c21985f3848" } move-table-extension = { git = "https://github.com/starcoinorg/move", rev = "0b3686b4edcd37fd0c61c1aa26859c21985f3848" } move-vm-test-utils = { git = "https://github.com/starcoinorg/move", rev = "0b3686b4edcd37fd0c61c1aa26859c21985f3848", features = ["table-extension"] } +read-write-set = { git = "https://github.com/starcoinorg/move", rev = "0b3686b4edcd37fd0c61c1aa26859c21985f3848" } names = { version = "0.14.0", default-features = false } network-api = { path = "network/api", package = "network-api" } @@ -495,6 +497,7 @@ starcoin-infallible = { path = "commons/infallible" } starcoin-block-executor = { path = "vm/block-executor" } starcoin-transaction-benchmarks = { path = "vm/transaction-benchmarks" } starcoin-language-e2e-tests = { path = "vm/e2e-tests" } +starcoin-language-e2e-testsuite = { path = "vm/e2e-testsuite" } starcoin-proptest-helpers = { path = "vm/proptest-helpers" } syn = { version = "1.0.107", features = [ diff --git a/commons/forkable-jellyfish-merkle/src/iterator/iterator_test.rs b/commons/forkable-jellyfish-merkle/src/iterator/iterator_test.rs index fbf4d648ae..d7c025ed84 100644 --- a/commons/forkable-jellyfish-merkle/src/iterator/iterator_test.rs +++ b/commons/forkable-jellyfish-merkle/src/iterator/iterator_test.rs @@ -9,7 +9,7 @@ // JellyfishMerkleTree, // }; // use anyhow::Result; -// use diem_crypto::HashValue; +// use starcoin_crypto::HashValue; // use diem_types::{account_state_blob::AccountStateBlob, transaction::Version}; // use rand::{rngs::StdRng, SeedableRng}; // use std::{collections::BTreeMap, sync::Arc}; diff --git a/vm/e2e-tests/src/versioning.rs b/vm/e2e-tests/src/versioning.rs index 33209bf1c9..6ed6ca4763 100644 --- a/vm/e2e-tests/src/versioning.rs +++ b/vm/e2e-tests/src/versioning.rs @@ -2,11 +2,15 @@ // SPDX-License-Identifier: Apache-2.0 #![forbid(unsafe_code)] + +use starcoin_vm_types::on_chain_config::G_VERSION_CONFIG_IDENTIFIER; use crate::{account::Account, executor::FakeExecutor, utils}; /// The current version numbers that e2e tests should be run against. // pub const CURRENT_RELEASE_VERSIONS: std::ops::RangeInclusive = -// starcoin_MAX_KNOWN_VERSION.major..=starcoin_MAX_KNOWN_VERSION.major; +// STARCOIN_MAX_KNOWN_VERSION.major..=STARCOIN_MAX_KNOWN_VERSION.major; + +pub const CURRENT_RELEASE_VERSIONS: std::ops::RangeInclusive = 1..=DIEM_MAX_KNOWN_VERSION.major; #[derive(Debug)] pub struct VersionedTestEnv { diff --git a/vm/e2e-testsuite/Cargo.toml b/vm/e2e-testsuite/Cargo.toml new file mode 100644 index 0000000000..a864d4f709 --- /dev/null +++ b/vm/e2e-testsuite/Cargo.toml @@ -0,0 +1,51 @@ +[package] +name = "starcoin-language-e2e-testsuite" +authors = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +publish = { workspace = true } +version = "1.13.7" +homepage = { workspace = true } +repository = { workspace = true } +rust-version = { workspace = true } + + +[dependencies] +serde_json = "1.0.64" +hex = "0.4.3" +bcs = "0.1.2" +proptest = "1.0.0" + +## Move dependencies +move-core-types = { workspace = true } +move-ir-compiler = { workspace = true } +move-vm-runtime = { workspace = true } +move-vm-types = { workspace = true } +move-binary-format = { workspace = true } +move-bytecode-verifier = { workspace = true } +read-write-set = { workspace = true } + +## Diem-Move dependencies +starcoin-language-e2e-tests = { workspace = true } +starcoin-logger = { workspace = true } +starcoin-transaction-builder = { workspace = true } +starcoin-vm-runtime = { workspace = true } +starcoin-vm-types = { workspace = true } +starcoin-types = { workspace = true } +starcoin-crypto = { workspace = true } +#diem-keygen = { path = "../diem-keygen" } +#starcoin-vm = { path = "../starcoin-vm" } +#diem-framework-releases = { path = "../diem-framework/DPN/releases" } +#diem-parallel-executor = { path = "../parallel-executor" } +#diem-writeset-generator = { path = "../writeset-transaction-generator"} + +## Other Diem dependencies +#diem-crypto = { path = "../../crates/diem-crypto", features = ["fuzzing"] } +#diem-types = { path = "../../types", features = ["fuzzing"] } +#diem-transaction-builder = { path = "../../sdk/transaction-builder"} +#diem-logger = { path = "../../crates/diem-logger" } +#diem-state-view = { path = "../../storage/state-view" } +#diem-workspace-hack = { version = "0.1", path = "../../crates/diem-workspace-hack" } + +#[features] +#default = ["starcoin-transaction-builder/fuzzing"] diff --git a/vm/e2e-testsuite/src/lib.rs b/vm/e2e-testsuite/src/lib.rs new file mode 100644 index 0000000000..463fcc9a14 --- /dev/null +++ b/vm/e2e-testsuite/src/lib.rs @@ -0,0 +1,5 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +#[cfg(test)] +mod tests; diff --git a/vm/e2e-testsuite/src/tests/account_limits.rs b/vm/e2e-testsuite/src/tests/account_limits.rs new file mode 100644 index 0000000000..a4bcddab35 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/account_limits.rs @@ -0,0 +1,732 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +#![forbid(unsafe_code)] + +use move_ir_compiler::Compiler; +use starcoin_language_e2e_tests::{ + account::{self, Account}, + current_function_name, + executor::FakeExecutor, +}; +use starcoin_types::{ + account_address::AccountAddress, + account_config, + transaction::{Script, TransactionArgument, TransactionOutput, WriteSetPayload}, +}; +use starcoin_transaction_builder::stdlib::*; + +fn assert_aborted_with(output: TransactionOutput, error_code: u64) { + assert!(matches!( + output.status().status(), + Ok(KeptVMStatus::MoveAbort(_, code)) if code == error_code + )); +} + +fn encode_add_account_limits_admin_script(execute_as: AccountAddress) -> WriteSetPayload { + let add_account_limits_admin_script = { + let code = " + import 0x1.AccountLimits; + import 0x1.XUS; + import 0x1.Signer; + + main(dr_account: signer, vasp: signer) { + label b0: + AccountLimits.publish_unrestricted_limits_for_testing(&vasp); + AccountLimits.publish_window( + &dr_account, + &vasp, + Signer.address_of(&vasp) + ); + return; + } +"; + let compiler = Compiler { + deps: starcoin_framework_releases::current_modules().iter().collect(), + }; + compiler.into_script_blob(code).expect("Failed to compile") + }; + + WriteSetPayload::Script { + script: Script::new(add_account_limits_admin_script, vec![], vec![]), + execute_as, + } +} + +fn encode_update_account_limit_definition_script( + limit_addr: AccountAddress, + new_max_inflow: u64, + new_max_outflow: u64, + new_max_holding_balance: u64, + new_time_period: u64, +) -> Script { + let script_body = { + let code = " + import 0x1.AccountLimits; + import 0x1.XUS; + + main( + account: signer, + limit_addr: address, + new_max_inflow: u64, + new_max_outflow: u64, + new_max_holding_balance: u64, + new_time_period: u64 + ) { + label b0: + AccountLimits.update_limits_definition( + &account, + move(limit_addr), + move(new_max_inflow), + move(new_max_outflow), + move(new_max_holding_balance), + move(new_time_period), + ); + return; + } +"; + let compiler = Compiler { + deps: starcoin_framework_releases::current_modules().iter().collect(), + }; + compiler.into_script_blob(code).expect("Failed to compile") + }; + + Script::new( + script_body, + vec![], + vec![ + TransactionArgument::Address(limit_addr), + TransactionArgument::U64(new_max_inflow), + TransactionArgument::U64(new_max_outflow), + TransactionArgument::U64(new_max_holding_balance), + TransactionArgument::U64(new_time_period), + ], + ) +} + +fn encode_update_account_limit_window_info_script( + window_addr: AccountAddress, + aggregate_balance: u64, + new_limit_address: AccountAddress, +) -> Script { + let script_body = { + let code = " + import 0x1.AccountLimits; + import 0x1.XUS; + + main(account: signer, + window_addr: address, + aggregate_balance: u64, + new_limit_address: address + ) { + label b0: + AccountLimits.update_window_info( + &account, + move(window_addr), + move(aggregate_balance), + move(new_limit_address), + ); + return; + } +"; + let compiler = Compiler { + deps: diem_framework_releases::current_modules().iter().collect(), + }; + compiler.into_script_blob(code).expect("Failed to compile") + }; + + Script::new( + script_body, + vec![], + vec![ + TransactionArgument::Address(window_addr), + TransactionArgument::U64(aggregate_balance), + TransactionArgument::Address(new_limit_address), + ], + ) +} + +#[test] +fn account_limits() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + let vasp_a = executor.create_raw_account(); + let vasp_b = executor.create_raw_account(); + let vasp_a_child = executor.create_raw_account(); + let vasp_b_child = executor.create_raw_account(); + let diem_root = Account::new_diem_root(); + let blessed = Account::new_blessed_tc(); + let dd = Account::new_testing_dd(); + let dr_sequence_number = 0; + let tc_sequence_number = 0; + let dd_sequence_number = 0; + + let mint_amount = 1_000_000; + let window_micros = 86400000000; + let ttl = window_micros; + + // Create vasp accounts + executor.execute_and_apply( + blessed + .transaction() + .script(encode_create_parent_vasp_account_script( + account_config::xus_tag(), + 0, + *vasp_a.address(), + vasp_a.auth_key_prefix(), + vec![], + true, + )) + .sequence_number(tc_sequence_number) + .ttl(ttl) + .sign(), + ); + executor.execute_and_apply( + blessed + .transaction() + .script(encode_create_parent_vasp_account_script( + account_config::xus_tag(), + 0, + *vasp_b.address(), + vasp_b.auth_key_prefix(), + vec![], + true, + )) + .sequence_number(tc_sequence_number.checked_add(1).unwrap()) + .ttl(ttl) + .sign(), + ); + + // Create child vasp accounts + executor.execute_and_apply( + vasp_a + .transaction() + .script(encode_create_child_vasp_account_script( + account_config::xus_tag(), + *vasp_a_child.address(), + vasp_a_child.auth_key_prefix(), + true, + 0, + )) + .sequence_number(0) + .ttl(ttl) + .sign(), + ); + executor.execute_and_apply( + vasp_b + .transaction() + .script(encode_create_child_vasp_account_script( + account_config::xus_tag(), + *vasp_b_child.address(), + vasp_b_child.auth_key_prefix(), + true, + 0, + )) + .sequence_number(0) + .ttl(ttl) + .sign(), + ); + + executor.execute_and_apply( + diem_root + .transaction() + .write_set(encode_add_account_limits_admin_script(*vasp_a.address())) + .sequence_number(dr_sequence_number) + .sign(), + ); + + executor.execute_and_apply( + diem_root + .transaction() + .write_set(encode_add_account_limits_admin_script(*vasp_b.address())) + .sequence_number(dr_sequence_number.checked_add(1).unwrap()) + .sign(), + ); + + // mint money to both vasp A & B + executor.execute_and_apply( + dd.transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_a.address(), + 2 * mint_amount, + vec![], + vec![], + )) + .sequence_number(dd_sequence_number) + .ttl(ttl) + .sign(), + ); + executor.execute_and_apply( + dd.transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_b.address(), + 2 * mint_amount, + vec![], + vec![], + )) + .sequence_number(dd_sequence_number.checked_add(1).unwrap()) + .ttl(ttl) + .sign(), + ); + + executor.execute_and_apply( + blessed + .transaction() + .script(encode_update_account_limit_window_info_script( + *vasp_a.address(), + 0, + *vasp_a.address(), + )) + .sequence_number(tc_sequence_number.checked_add(2).unwrap()) + .ttl(ttl) + .sign(), + ); + + /////////////////////////////////////////////////////////////////////////// + // Inflow tests + ///////////////////////////////////////////////////////////////////////////// + + // Set vasp A's inflow limit to half of what we just minted them + executor.execute_and_apply( + blessed + .transaction() + .script(encode_update_account_limit_definition_script( + *vasp_a.address(), + mint_amount, + 0, + 0, + 0, + )) + .sequence_number(tc_sequence_number.checked_add(3).unwrap()) + .ttl(ttl) + .sign(), + ); + + { + // Now try and pay in to vasp A; fails since inflow is exceeded + let output = executor.execute_transaction( + vasp_b + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_a.address(), + mint_amount + 1, + vec![], + vec![], + )) + .sequence_number(1) + .ttl(ttl) + .sign(), + ); + assert_aborted_with(output, 776); + } + + { + // Now try and pay in to child of vasp A; fails since inflow is exceeded + let output = executor.execute_transaction( + vasp_b + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_a_child.address(), + mint_amount + 1, + vec![], + vec![], + )) + .sequence_number(1) + .ttl(ttl) + .sign(), + ); + assert_aborted_with(output, 776); + } + + // Intra-vasp transfer isn't limited + executor.execute_and_apply( + vasp_a + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_a_child.address(), + mint_amount + 1, + vec![], + vec![], + )) + .sequence_number(1) + .ttl(ttl) + .sign(), + ); + + // Only inflow is limited; can send from vasp a still + executor.execute_and_apply( + vasp_a_child + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_b_child.address(), + mint_amount + 1, + vec![], + vec![], + )) + .sequence_number(0) + .ttl(ttl) + .sign(), + ); + + // The previous mints don't count in this window since it wasn't a vasp->vasp transfer + executor.execute_and_apply( + vasp_b_child + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_a_child.address(), + mint_amount, + vec![], + vec![], + )) + .sequence_number(0) + .ttl(ttl) + .sign(), + ); + + { + // DD deposit fails since vasp A is at inflow limit + let output = executor.execute_transaction( + dd.transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_a_child.address(), + 1, + vec![], + vec![], + )) + .sequence_number(dd_sequence_number.checked_add(2).unwrap()) + .ttl(ttl) + .sign(), + ); + assert_aborted_with(output, 776); + + // Reset the window + let prev_block_time = executor.get_block_time(); + executor.set_block_time(prev_block_time + window_micros); + executor.new_block(); + + // DD deposit now succeeds since window is reset + let output = executor.execute_transaction( + dd.transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_a_child.address(), + 1, + vec![], + vec![], + )) + .sequence_number(dd_sequence_number.checked_add(2).unwrap()) + .ttl(ttl) + .sign(), + ); + assert_eq!(output.status().status(), Ok(KeptVMStatus::Executed)); + } + + /////////////////////////////////////////////////////////////////////////// + // Outflow tests + ///////////////////////////////////////////////////////////////////////////// + + // Set vasp A's outflow to 1000 + executor.execute_and_apply( + blessed + .transaction() + .script(encode_update_account_limit_definition_script( + *vasp_a.address(), + std::u64::MAX, // unlimit inflow + 1000, // set outflow to 1000 + 0, + 0, + )) + .sequence_number(tc_sequence_number.checked_add(4).unwrap()) + .ttl(ttl) + .sign(), + ); + + // Intra-vasp transfer isn't limited + executor.execute_and_apply( + vasp_a + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_a_child.address(), + 1001, + vec![], + vec![], + )) + .sequence_number(2) + .ttl(ttl) + .sign(), + ); + + // Can send up to the limit inter-vasp: + executor.execute_and_apply( + vasp_a_child + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_b_child.address(), + 1000, + vec![], + vec![], + )) + .sequence_number(1) + .ttl(ttl) + .sign(), + ); + + { + // Inter-vasp transfer is limited + let output = executor.execute_transaction( + vasp_a + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_b.address(), + 1, + vec![], + vec![], + )) + .sequence_number(3) + .ttl(ttl) + .sign(), + ); + assert_aborted_with(output, 1544); + } + + { + // Inter-vasp transfer is limited; holds between children too + let output = executor.execute_transaction( + vasp_a_child + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_b_child.address(), + 1, + vec![], + vec![], + )) + .sequence_number(2) + .ttl(ttl) + .sign(), + ); + assert_aborted_with(output, 1544); + } + + { + // vasp->anything transfer is limited + let output = executor.execute_transaction( + vasp_a_child + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *dd.address(), + 1, + vec![], + vec![], + )) + .sequence_number(2) + .ttl(ttl) + .sign(), + ); + assert_aborted_with(output, 1544); + + // update block time + let prev_block_time = executor.get_block_time(); + executor.set_block_time(prev_block_time + window_micros); + executor.new_block(); + + let output = executor.execute_transaction( + vasp_a_child + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *dd.address(), + 1, + vec![], + vec![], + )) + .sequence_number(2) + .ttl(window_micros) + .ttl(ttl) + .sign(), + ); + assert_eq!(output.status().status(), Ok(KeptVMStatus::Executed),); + } + + /////////////////////////////////////////////////////////////////////////// + // Holding tests + ///////////////////////////////////////////////////////////////////////////// + + // Set vasp A's max holding to its current balance across all accounts + { + let a_parent_balance = executor + .read_balance_resource(&vasp_a, account::xus_currency_code()) + .unwrap() + .coin(); + let a_child_balance = executor + .read_balance_resource(&vasp_a_child, account::xus_currency_code()) + .unwrap() + .coin(); + let a_balance = a_parent_balance + a_child_balance; + executor.execute_and_apply( + blessed + .transaction() + .script(encode_update_account_limit_definition_script( + *vasp_a.address(), + 0, + std::u64::MAX, // unlimit outflow + a_balance, // set max holding to the current balance of A + 0, + )) + .sequence_number(tc_sequence_number.checked_add(5).unwrap()) + .ttl(ttl) + .sign(), + ); + // TC needs to set the current aggregate balance for vasp a's window + executor.execute_and_apply( + blessed + .transaction() + .script(encode_update_account_limit_window_info_script( + *vasp_a.address(), + a_balance, + *vasp_a.address(), + )) + .sequence_number(tc_sequence_number.checked_add(6).unwrap()) + .ttl(ttl) + .sign(), + ); + } + + // inter-vasp: fails since limit is set at A's current balance + { + let output = executor.execute_transaction( + vasp_b + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_a_child.address(), + 1, + vec![], + vec![], + )) + .sequence_number(1) + .ttl(ttl) + .sign(), + ); + assert_aborted_with(output, 776); + } + + // Fine since A can still send + executor.execute_and_apply( + vasp_a + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_b_child.address(), + 10, + vec![], + vec![], + )) + .sequence_number(3) + .ttl(ttl) + .sign(), + ); + + // inter-vasp: OK since A's total balance = limit - 10 + executor.execute_and_apply( + vasp_b + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_a_child.address(), + 10, + vec![], + vec![], + )) + .sequence_number(1) + .ttl(ttl) + .sign(), + ); + + { + // inter-vasp: should now fail again + let output = executor.execute_transaction( + vasp_b + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_a_child.address(), + 1, + vec![], + vec![], + )) + .sequence_number(2) + .ttl(ttl) + .sign(), + ); + assert_aborted_with(output, 776); + } + + // intra-vasp: OK since it isn't checked/contributes to the total balance + executor.execute_and_apply( + vasp_a_child + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_a.address(), + 1100, + vec![], + vec![], + )) + .sequence_number(2) + .ttl(ttl) + .sign(), + ); + + { + // DD deposit fails since vasp A is at holding limit + let output = executor.execute_transaction( + dd.transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_a_child.address(), + 1, + vec![], + vec![], + )) + .sequence_number(dd_sequence_number.checked_add(2).unwrap()) + .ttl(ttl) + .sign(), + ); + assert_aborted_with(output, 776); + + // Reset window + let prev_block_time = executor.get_block_time(); + executor.set_block_time(prev_block_time + window_micros); + executor.new_block(); + + // DD deposit fails since vasp A is at holding limit + // and because holdings are not reset from one window to the next. + let output = executor.execute_transaction( + dd.transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *vasp_a_child.address(), + 1, + vec![], + vec![], + )) + .sequence_number(dd_sequence_number.checked_add(2).unwrap()) + .ttl(ttl) + .sign(), + ); + assert_aborted_with(output, 776); + } +} diff --git a/vm/e2e-testsuite/src/tests/account_universe/bad_transaction.rs b/vm/e2e-testsuite/src/tests/account_universe/bad_transaction.rs new file mode 100644 index 0000000000..85ccf45883 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/account_universe/bad_transaction.rs @@ -0,0 +1,37 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use proptest::{collection::vec, prelude::*}; +use starcoin_language_e2e_tests::account_universe::{ + default_num_transactions, run_and_assert_gas_cost_stability, AccountUniverseGen, + InsufficientBalanceGen, InvalidAuthkeyGen, SequenceNumberMismatchGen, +}; + +proptest! { + // These tests are pretty slow but quite comprehensive, so run a smaller number of them. + #![proptest_config(ProptestConfig::with_cases(32))] + + #[test] + fn bad_sequence( + universe in AccountUniverseGen::success_strategy(2), + txns in vec(any_with::((0, 10_000)), 0..default_num_transactions()), + ) { + run_and_assert_gas_cost_stability(universe, txns)?; + } + + #[test] + fn bad_auth_key( + universe in AccountUniverseGen::success_strategy(2), + txns in vec(any_with::(()), 0..default_num_transactions()), + ) { + run_and_assert_gas_cost_stability(universe, txns)?; + } + + #[test] + fn insufficient_balance( + universe in AccountUniverseGen::success_strategy(2), + txns in vec(any_with::((1, 10_001)), 0..default_num_transactions()), + ) { + run_and_assert_gas_cost_stability(universe, txns)?; + } +} diff --git a/vm/e2e-testsuite/src/tests/account_universe/create_account.rs b/vm/e2e-testsuite/src/tests/account_universe/create_account.rs new file mode 100644 index 0000000000..fb7c691f4a --- /dev/null +++ b/vm/e2e-testsuite/src/tests/account_universe/create_account.rs @@ -0,0 +1,78 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +// TODO: all of these tests rely on a symmetric account creation mechanism; that is, an account of +// type T that can create another account of type T. This does not exist in the current system, but +// will exist once we introduce unhosted wallets. Will bring these back once we enable unhosted +// wallets +/*proptest! { + // These tests are pretty slow but quite comprehensive, so run a smaller number of them. + #![proptest_config(ProptestConfig::with_cases(32))] + + // Need a minimum of one account for create_account. + // Set balances high enough that transactions will always succeed. + #[test] + fn create_account_gas_cost_stability( + universe in AccountUniverseGen::success_strategy(1), + transfers in vec(any_with::((1, 10_000)), 0..default_num_transactions()), + ) { + run_and_assert_gas_cost_stability(universe, transfers)?; + } + + #[test] + fn create_account_high_balance( + universe in AccountUniverseGen::strategy(1..default_num_accounts(), 1_000_000u64..10_000_000), + transfers in vec(any_with::((1, 10_000)), 0..default_num_transactions()), + ) { + run_and_assert_universe(universe, transfers)?; + } + + /// Test with balances small enough to possibly trigger failures. + #[test] + fn create_account_low_balance( + universe in AccountUniverseGen::strategy(1..default_num_accounts(), 0u64..100_000), + transfers in vec(any_with::((1, 50_000)), 0..default_num_transactions()), + ) { + run_and_assert_universe(universe, transfers)?; + } + + // Need a minimum of two accounts for create account with existing receiver. + // Set balances high enough that transactions will always succeed. + #[test] + fn create_existing_account_gas_cost_stability( + universe in AccountUniverseGen::success_strategy(2), + transfers in vec( + any_with::((1, 10_000)), + 0..default_num_transactions(), + ), + ) { + run_and_assert_gas_cost_stability(universe, transfers)?; + } + + #[test] + fn create_existing_account( + universe in AccountUniverseGen::strategy( + 2..default_num_accounts(), + log_balance_strategy(10_000_000), + ), + transfers in vec( + any_with::((1, 1_000_000)), + 0..default_num_transactions(), + ), + ) { + run_and_assert_universe(universe, transfers)?; + } + + /// Mixed tests with the different kinds of create-account transactions and a large variety + /// of balances. + #[test] + fn create_account_mixed( + universe in AccountUniverseGen::strategy( + 2..default_num_accounts(), + log_balance_strategy(10_000_000), + ), + transfers in vec(create_account_strategy(1, 1_000_000), 0..default_num_transactions()), + ) { + run_and_assert_universe(universe, transfers)?; + } +}*/ diff --git a/vm/e2e-testsuite/src/tests/account_universe/mod.rs b/vm/e2e-testsuite/src/tests/account_universe/mod.rs new file mode 100644 index 0000000000..2280cc8373 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/account_universe/mod.rs @@ -0,0 +1,84 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +mod bad_transaction; +mod create_account; +mod peer_to_peer; +mod rotate_key; + +use proptest::{collection::vec, prelude::*}; +use starcoin_language_e2e_tests::{ + account_universe::{ + all_transactions_strategy, default_num_accounts, default_num_transactions, + log_balance_strategy, run_and_assert_universe, AccountCurrent, AccountPairGen, + AccountPickStyle, AccountUniverseGen, + }, + executor::FakeExecutor, +}; + +proptest! { + // These tests are pretty slow but quite comprehensive, so run a smaller number of them. + #![proptest_config(ProptestConfig::with_cases(32))] + + /// Ensure that account pair generators return the correct indexes. + #[test] + fn account_pair_gen( + universe in AccountUniverseGen::strategy(2..default_num_accounts(), 0u64..10000), + pairs in vec(any::(), 0..default_num_transactions()), + ) { + let mut executor = FakeExecutor::from_genesis_file(); + let mut universe = universe.setup(&mut executor); + + for pair in pairs { + let (idx_1, idx_2, account_1, account_2) = { + let pick = pair.pick(&mut universe); + ( + pick.idx_1, + pick.idx_2, + // Need to convert to raw pointers to avoid holding a mutable reference + // (pick_mut below borrows universe mutably, which would conflict.) + // This is safe as all we're doing is comparing pointer equality. + pick.account_1 as *const AccountCurrent, + pick.account_2 as *const AccountCurrent, + ) + }; + + prop_assert_eq!(account_1, &universe.accounts()[idx_1] as *const AccountCurrent); + prop_assert_eq!(account_2, &universe.accounts()[idx_2] as *const AccountCurrent); + } + } + + #[test] + fn all_transactions( + universe in AccountUniverseGen::strategy( + 2..default_num_accounts(), + log_balance_strategy(10_000_000), + ), + transactions in vec(all_transactions_strategy(1, 1_000_000), 0..default_num_transactions()), + ) { + run_and_assert_universe(universe, transactions)?; + } + + #[test] + fn all_transactions_limited( + mut universe in AccountUniverseGen::strategy( + 4..default_num_accounts(), + log_balance_strategy(10_000_000), + ), + mut transactions in vec( + all_transactions_strategy(1, 1_000_000), + 0..default_num_transactions(), + ), + ) { + universe.set_pick_style(AccountPickStyle::Limited(4)); + // Each transaction consumes up to 2 slots, and there are (4 * universe.num_accounts()) + // slots. Use only 3/4 of the slots to allow for some tolerance against edge cases. So + // the maximum number of transactions is (3 * universe.num_accounts()) / 2. + let max_transactions = (3 * universe.num_accounts()) / 2; + if transactions.len() >= max_transactions { + transactions.drain(max_transactions..); + } + + run_and_assert_universe(universe, transactions)?; + } +} diff --git a/vm/e2e-testsuite/src/tests/account_universe/peer_to_peer.rs b/vm/e2e-testsuite/src/tests/account_universe/peer_to_peer.rs new file mode 100644 index 0000000000..44ba9a511b --- /dev/null +++ b/vm/e2e-testsuite/src/tests/account_universe/peer_to_peer.rs @@ -0,0 +1,56 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use proptest::{collection::vec, prelude::*}; +use starcoin_language_e2e_tests::account_universe::{ + default_num_accounts, default_num_transactions, log_balance_strategy, p2p_strategy, + run_and_assert_gas_cost_stability, run_and_assert_universe, AccountUniverseGen, P2PTransferGen, +}; + +proptest! { + // These tests are pretty slow but quite comprehensive, so run a smaller number of them. + #![proptest_config(ProptestConfig::with_cases(32))] + + // Need a minimum of two accounts to send p2p transactions over. + // Set balances high enough that transactions will always succeed. + #[test] + fn p2p_gas_cost_stability( + universe in AccountUniverseGen::success_strategy(2), + transfers in vec(any_with::((1, 10_000)), 0..default_num_transactions()), + ) { + run_and_assert_gas_cost_stability(universe, transfers)?; + } + + #[test] + fn p2p_high_balance( + universe in AccountUniverseGen::strategy( + 2..default_num_accounts(), + 1_000_000u64..10_000_000, + ), + transfers in vec(any_with::((1, 10_000)), 0..default_num_transactions()), + ) { + run_and_assert_universe(universe, transfers)?; + } + + /// Test with balances small enough to possibly trigger failures. + #[test] + fn p2p_low_balance( + universe in AccountUniverseGen::strategy(2..default_num_accounts(), 0u64..100_000), + transfers in vec(any_with::((1, 50_000)), 0..default_num_transactions()), + ) { + run_and_assert_universe(universe, transfers)?; + } + + /// Mixed tests with all the different kinds of peer to peer transactions and a large + /// variety of balances. + #[test] + fn p2p_mixed( + universe in AccountUniverseGen::strategy( + 2..default_num_accounts(), + log_balance_strategy(10_000_000), + ), + transfers in vec(p2p_strategy(1, 1_000_000), 0..default_num_transactions()), + ) { + run_and_assert_universe(universe, transfers)?; + } +} diff --git a/vm/e2e-testsuite/src/tests/account_universe/rotate_key.rs b/vm/e2e-testsuite/src/tests/account_universe/rotate_key.rs new file mode 100644 index 0000000000..9d531d12a8 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/account_universe/rotate_key.rs @@ -0,0 +1,40 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use proptest::{collection::vec, prelude::*}; +use starcoin_language_e2e_tests::account_universe::{ + default_num_accounts, default_num_transactions, run_and_assert_gas_cost_stability, + run_and_assert_universe, AccountUniverseGen, RotateKeyGen, +}; + +proptest! { + // These tests are pretty slow but quite comprehensive, so run a smaller number of them. + #![proptest_config(ProptestConfig::with_cases(32))] + + #[test] + fn rotate_key_gas_cost_stability( + universe in AccountUniverseGen::success_strategy(1), + key_rotations in vec(any::(), 0..default_num_transactions()), + ) { + run_and_assert_gas_cost_stability(universe, key_rotations)?; + } + + #[test] + fn rotate_key_high_balance( + universe in AccountUniverseGen::strategy( + 1..default_num_accounts(), + 1_000_000u64..10_000_000, + ), + key_rotations in vec(any::(), 0..default_num_transactions()), + ) { + run_and_assert_universe(universe, key_rotations)?; + } + + #[test] + fn rotate_key_low_balance( + universe in AccountUniverseGen::strategy(1..default_num_accounts(), 0u64..100_000), + key_rotations in vec(any::(), 0..default_num_transactions()), + ) { + run_and_assert_universe(universe, key_rotations)?; + } +} diff --git a/vm/e2e-testsuite/src/tests/admin_script.rs b/vm/e2e-testsuite/src/tests/admin_script.rs new file mode 100644 index 0000000000..38066340b4 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/admin_script.rs @@ -0,0 +1,188 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use starcoin_language_e2e_tests::{ + account::Account, current_function_name, executor::FakeExecutor, +}; + +use starcoin_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, Uniform}; +use diem_types::{ + transaction::{authenticator::AuthenticationKey, Script, TransactionArgument}, + vm_status::StatusCode, +}; + +use diem_types::transaction::WriteSetPayload; +use move_ir_compiler::Compiler; + +#[test] +fn admin_script_rotate_key_single_signer_no_epoch() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + let new_account = executor.create_raw_account_data(100_000, 0); + executor.add_account_data(&new_account); + + let privkey = Ed25519PrivateKey::generate_for_testing(); + let pubkey = privkey.public_key(); + let new_key_hash = AuthenticationKey::ed25519(&pubkey).to_vec(); + + let script_body = { + let code = r#" +import 0x1.DiemAccount; + +main(dr_account: signer, account: signer, auth_key_prefix: vector) { + let rotate_cap: DiemAccount.KeyRotationCapability; +label b0: + rotate_cap = DiemAccount.extract_key_rotation_capability(&account); + DiemAccount.rotate_authentication_key(&rotate_cap, move(auth_key_prefix)); + DiemAccount.restore_key_rotation_capability(move(rotate_cap)); + + return; +} +"#; + + let compiler = Compiler { + deps: diem_framework_releases::current_modules().iter().collect(), + }; + compiler.into_script_blob(code).expect("Failed to compile") + }; + let account = Account::new_diem_root(); + let txn = account + .transaction() + .write_set(WriteSetPayload::Script { + script: Script::new( + script_body, + vec![], + vec![TransactionArgument::U8Vector(new_key_hash.clone())], + ), + execute_as: *new_account.address(), + }) + .sequence_number(0) + .sign(); + executor.new_block(); + let output = executor.execute_and_apply(txn); + + // The transaction should not trigger a reconfiguration. + let new_epoch_event_key = diem_types::on_chain_config::new_epoch_event_key(); + assert!(!output + .events() + .iter() + .any(|event| *event.key() == new_epoch_event_key)); + + let updated_sender = executor + .read_account_resource(new_account.account()) + .expect("sender must exist"); + + assert_eq!(updated_sender.authentication_key(), new_key_hash.as_slice()); +} + +#[test] +fn admin_script_rotate_key_single_signer_new_epoch() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + let new_account = executor.create_raw_account_data(100_000, 0); + executor.add_account_data(&new_account); + + let privkey = Ed25519PrivateKey::generate_for_testing(); + let pubkey = privkey.public_key(); + let new_key_hash = AuthenticationKey::ed25519(&pubkey).to_vec(); + + let script_body = { + let code = r#" +import 0x1.DiemAccount; +import 0x1.DiemConfig; + +main(dr_account: signer, account: signer, auth_key_prefix: vector) { + let rotate_cap: DiemAccount.KeyRotationCapability; +label b0: + rotate_cap = DiemAccount.extract_key_rotation_capability(&account); + DiemAccount.rotate_authentication_key(&rotate_cap, move(auth_key_prefix)); + DiemAccount.restore_key_rotation_capability(move(rotate_cap)); + + DiemConfig.reconfigure(&dr_account); + return; +} +"#; + + let compiler = Compiler { + deps: diem_framework_releases::current_modules().iter().collect(), + }; + compiler.into_script_blob(code).expect("Failed to compile") + }; + let account = Account::new_diem_root(); + let txn = account + .transaction() + .write_set(WriteSetPayload::Script { + script: Script::new( + script_body, + vec![], + vec![TransactionArgument::U8Vector(new_key_hash.clone())], + ), + execute_as: *new_account.address(), + }) + .sequence_number(0) + .sign(); + executor.new_block(); + let output = executor.execute_and_apply(txn); + + // The transaction should trigger a reconfiguration. + let new_epoch_event_key = diem_types::on_chain_config::new_epoch_event_key(); + assert!(output + .events() + .iter() + .any(|event| *event.key() == new_epoch_event_key)); + + let updated_sender = executor + .read_account_resource(new_account.account()) + .expect("sender must exist"); + + assert_eq!(updated_sender.authentication_key(), new_key_hash.as_slice()); +} + +#[test] +fn admin_script_rotate_key_multi_signer() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + let new_account = executor.create_raw_account_data(100_000, 0); + executor.add_account_data(&new_account); + + let privkey = Ed25519PrivateKey::generate_for_testing(); + let pubkey = privkey.public_key(); + let new_key_hash = AuthenticationKey::ed25519(&pubkey).to_vec(); + + let script_body = { + let code = r#" +import 0x1.DiemAccount; + +main(account: signer, auth_key_prefix: vector) { + let rotate_cap: DiemAccount.KeyRotationCapability; +label b0: + rotate_cap = DiemAccount.extract_key_rotation_capability(&account); + DiemAccount.rotate_authentication_key(&rotate_cap, move(auth_key_prefix)); + DiemAccount.restore_key_rotation_capability(move(rotate_cap)); + + return; +} +"#; + + let compiler = Compiler { + deps: diem_framework_releases::current_modules().iter().collect(), + }; + compiler.into_script_blob(code).expect("Failed to compile") + }; + let account = Account::new_diem_root(); + let txn = account + .transaction() + .write_set(WriteSetPayload::Script { + script: Script::new( + script_body, + vec![], + vec![TransactionArgument::U8Vector(new_key_hash)], + ), + execute_as: *new_account.address(), + }) + .sequence_number(0) + .sign(); + executor.new_block(); + let output = executor.execute_transaction(txn); + assert_eq!(output.status().status(), Err(StatusCode::INVALID_WRITE_SET)); +} diff --git a/vm/e2e-testsuite/src/tests/create_account.rs b/vm/e2e-testsuite/src/tests/create_account.rs new file mode 100644 index 0000000000..5f488b95ff --- /dev/null +++ b/vm/e2e-testsuite/src/tests/create_account.rs @@ -0,0 +1,49 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use diem_types::{account_config, transaction::TransactionStatus, vm_status::KeptVMStatus}; +use starcoin_language_e2e_tests::{ + account::{self, Account}, + common_transactions::create_account_txn, + current_function_name, + executor::FakeExecutor, +}; + +#[test] +fn create_account() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + + // create and publish a sender with 1_000_000 coins + let sender = Account::new_blessed_tc(); + let new_account = executor.create_raw_account(); + + // define the arguments to the create account transaction + let initial_amount = 0; + let txn = create_account_txn( + &sender, + &new_account, + 0, + initial_amount, + account_config::xus_tag(), + ); + + // execute transaction + let output = executor.execute_transaction(txn); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + executor.apply_write_set(output.write_set()); + + // check that numbers in stored DB are correct + let updated_sender = executor + .read_account_resource(&sender) + .expect("sender must exist"); + + let updated_receiver_balance = executor + .read_balance_resource(&new_account, account::xus_currency_code()) + .expect("receiver balance must exist"); + assert_eq!(initial_amount, updated_receiver_balance.coin()); + assert_eq!(1, updated_sender.sequence_number()); +} diff --git a/vm/e2e-testsuite/src/tests/crsn.rs b/vm/e2e-testsuite/src/tests/crsn.rs new file mode 100644 index 0000000000..70bc9628b5 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/crsn.rs @@ -0,0 +1,298 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 +use diem_transaction_builder::stdlib; +use diem_types::{account_config, vm_status::StatusCode}; +use starcoin_language_e2e_tests::{ + account::Account, compile::compile_script, current_function_name, executor::FakeExecutor, +}; + +// The CRSN size used throughout the tests +const K: u64 = 10; + +fn init(executor: &mut FakeExecutor) { + let dr = Account::new_diem_root(); + let program = r#" + import 0x1.CRSN; + main(account: signer) { + label b0: + CRSN.allow_crsns(&account); + return; + } + "#; + let script = compile_script(program, vec![]); + let txn = dr.transaction().script(script).sequence_number(0).sign(); + executor.execute_and_apply(txn); +} + +#[test] +fn can_opt_in_to_crsn() { + let mut executor = FakeExecutor::from_genesis_file(); + // set the diem version back + let sender = executor.create_raw_account_data(1_000_010, 0); + executor.add_account_data(&sender); + executor.set_golden_file(current_function_name!()); + init(&mut executor); + + // This should apply + let txn = sender + .account() + .transaction() + .payload(stdlib::encode_opt_in_to_crsn_script_function(K)) + .sequence_number(0) + .sign(); + executor.execute_and_apply(txn); + + let txn = sender + .account() + .transaction() + .payload(stdlib::encode_peer_to_peer_with_metadata_script_function( + account_config::xus_tag(), + *sender.address(), + 100, + vec![], + vec![], + )) + .sequence_number(1) + .sign(); + executor.execute_and_apply(txn); +} + +#[test] +fn crsns_prevent_replay_window_shift() { + let mut executor = FakeExecutor::from_genesis_file(); + // set the diem version back + let sender = executor.create_raw_account_data(1_000_010, 0); + executor.add_account_data(&sender); + executor.set_golden_file(current_function_name!()); + init(&mut executor); + + // This should apply + let txn = sender + .account() + .transaction() + .payload(stdlib::encode_opt_in_to_crsn_script_function(K)) + .sequence_number(0) + .sign(); + executor.execute_and_apply(txn); + + let txn = sender + .account() + .transaction() + .payload(stdlib::encode_peer_to_peer_with_metadata_script_function( + account_config::xus_tag(), + *sender.address(), + 100, + vec![], + vec![], + )) + .sequence_number(1) + .sign(); + executor.execute_and_apply(txn.clone()); + let output = executor.execute_transaction(txn); + assert_eq!( + output.status().status().unwrap_err(), + StatusCode::SEQUENCE_NONCE_INVALID + ); +} + +#[test] +fn crsns_prevent_replay_no_window_shift() { + let mut executor = FakeExecutor::from_genesis_file(); + // set the diem version back + let sender = executor.create_raw_account_data(1_000_010, 0); + executor.add_account_data(&sender); + executor.set_golden_file(current_function_name!()); + init(&mut executor); + + // This should apply + let txn = sender + .account() + .transaction() + .payload(stdlib::encode_opt_in_to_crsn_script_function(K)) + .sequence_number(0) + .sign(); + executor.execute_and_apply(txn); + + let txn = sender + .account() + .transaction() + .payload(stdlib::encode_peer_to_peer_with_metadata_script_function( + account_config::xus_tag(), + *sender.address(), + 100, + vec![], + vec![], + )) + .sequence_number(10) + .sign(); + executor.execute_and_apply(txn.clone()); + + let output = executor.execute_transaction(txn); + assert_eq!( + output.status().status().unwrap_err(), + StatusCode::SEQUENCE_NONCE_INVALID + ); +} + +#[test] +fn crsns_can_be_executed_out_of_order() { + let mut executor = FakeExecutor::from_genesis_file(); + // set the diem version back + let sender = executor.create_raw_account_data(1_000_010, 0); + executor.add_account_data(&sender); + executor.set_golden_file(current_function_name!()); + init(&mut executor); + + // This should apply + let txn = sender + .account() + .transaction() + .payload(stdlib::encode_opt_in_to_crsn_script_function(K)) + .sequence_number(0) + .sign(); + executor.execute_and_apply(txn); + + let mut txns = Vec::new(); + + // worst-case scenario for out-of-order execution + for i in 0..K { + let txn = sender + .account() + .transaction() + .payload(stdlib::encode_peer_to_peer_with_metadata_script_function( + account_config::xus_tag(), + *sender.address(), + 100, + vec![], + vec![], + )) + .sequence_number(K - i) + .sign(); + txns.push(txn); + } + + for output in executor.execute_block_and_keep_vm_status(txns).unwrap() { + assert_eq!(output.0.status_code(), StatusCode::EXECUTED); + } +} + +#[test] +fn force_expiration_of_crsns() { + let mut executor = FakeExecutor::from_genesis_file(); + // set the diem version back + let sender = executor.create_raw_account_data(1_000_010, 0); + executor.add_account_data(&sender); + executor.set_golden_file(current_function_name!()); + init(&mut executor); + + // This should apply + let txn = sender + .account() + .transaction() + .payload(stdlib::encode_opt_in_to_crsn_script_function(K)) + .sequence_number(0) + .sign(); + executor.execute_and_apply(txn); + + // worst-case scenario for out-of-order execution + for i in K / 2..K { + let txn = sender + .account() + .transaction() + .payload(stdlib::encode_peer_to_peer_with_metadata_script_function( + account_config::xus_tag(), + *sender.address(), + 100, + vec![], + vec![], + )) + .sequence_number(i) + .sign(); + executor.execute_and_apply(txn); + } + + let txn = sender + .account() + .transaction() + .payload(stdlib::encode_peer_to_peer_with_metadata_script_function( + account_config::xus_tag(), + *sender.address(), + 100, + vec![], + vec![], + )) + .sequence_number(K + 1) + .sign(); + let output = executor.execute_transaction(txn); + assert_eq!( + output.status().status().unwrap_err(), + StatusCode::SEQUENCE_NONCE_INVALID + ); + + let txn = sender + .account() + .transaction() + .payload(stdlib::encode_force_expire_script_function(2 * K)) + .sequence_number(2) + .sign(); + let output = executor.execute_and_apply(txn); + + // Make sure a force shift event is emitted, that we can deserialize it to the event Rust struct + // and that it is what we expect + let x = &output.events()[0]; + let force_shift = + account_config::force_shift::ForceShiftEvent::try_from_bytes(x.event_data()).unwrap(); + assert_eq!(force_shift.current_min_nonce(), 1); + assert_eq!(force_shift.shift_amount(), 2 * K); + assert_eq!( + force_shift.bits_at_shift(), + vec![false, false, false, false, true, true, true, true, true, false] + ); + + let mut txns = Vec::new(); + + // Check that the old range is expired + for i in 0..2 * K + 1 { + let txn = sender + .account() + .transaction() + .payload(stdlib::encode_peer_to_peer_with_metadata_script_function( + account_config::xus_tag(), + *sender.address(), + 100, + vec![], + vec![], + )) + .sequence_number(i) + .sign(); + txns.push(txn); + } + + for output in executor.execute_block_and_keep_vm_status(txns).unwrap() { + assert_eq!(output.0.status_code(), StatusCode::SEQUENCE_NONCE_INVALID); + } + + let mut txns = Vec::new(); + + // and that the new range works + for i in 0..K { + let txn = sender + .account() + .transaction() + .payload(stdlib::encode_peer_to_peer_with_metadata_script_function( + account_config::xus_tag(), + *sender.address(), + 100, + vec![], + vec![], + )) + .sequence_number(3 * K - i) + .sign(); + + txns.push(txn); + } + + for output in executor.execute_block_and_keep_vm_status(txns).unwrap() { + assert_eq!(output.0.status_code(), StatusCode::EXECUTED); + } +} diff --git a/vm/e2e-testsuite/src/tests/data_store.rs b/vm/e2e-testsuite/src/tests/data_store.rs new file mode 100644 index 0000000000..7a0e8ea438 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/data_store.rs @@ -0,0 +1,373 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use diem_types::{ + transaction::{Module, SignedTransaction, Transaction, TransactionStatus}, + vm_status::KeptVMStatus, +}; +use move_binary_format::CompiledModule; +use move_bytecode_verifier::verify_module; +use move_ir_compiler::Compiler; +use starcoin_language_e2e_tests::{ + account::AccountData, compile::compile_script, current_function_name, executor::FakeExecutor, +}; + +#[test] +fn move_from_across_blocks() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + // publish module with add and remove resource + let (module, txn) = add_module_txn(&sender, 10); + executor.execute_and_apply(txn); + + // remove resource fails given no resource were published + let rem_txn = remove_resource_txn(&sender, 11, vec![module.clone()]); + let output = executor.execute_transaction(rem_txn); + assert!(matches!( + output.status().status(), + // StatusCode::MISSING_DATA + Ok(KeptVMStatus::ExecutionFailure { .. }) + )); + executor.apply_write_set(output.write_set()); + + // publish resource + let add_txn = add_resource_txn(&sender, 12, vec![module.clone()]); + executor.execute_and_apply(add_txn); + + // borrow resource + let borrow_txn = borrow_resource_txn(&sender, 13, vec![module.clone()]); + executor.execute_and_apply(borrow_txn); + + // remove resource + let rem_txn = remove_resource_txn(&sender, 14, vec![module.clone()]); + executor.execute_and_apply(rem_txn); + + // remove resource fails given it was removed already + let rem_txn = remove_resource_txn(&sender, 15, vec![module.clone()]); + let output = executor.execute_transaction(rem_txn); + assert!(matches!( + output.status().status(), + // StatusCode::MISSING_DATA + Ok(KeptVMStatus::ExecutionFailure { .. }) + )); + executor.apply_write_set(output.write_set()); + + // borrow resource fail given it was removed + let borrow_txn = borrow_resource_txn(&sender, 16, vec![module.clone()]); + let output = executor.execute_transaction(borrow_txn); + assert!(matches!( + output.status().status(), + // StatusCode::MISSING_DATA + Ok(KeptVMStatus::ExecutionFailure { .. }) + )); + executor.apply_write_set(output.write_set()); + + // publish resource again + let add_txn = add_resource_txn(&sender, 17, vec![module.clone()]); + executor.execute_and_apply(add_txn); + + // create 2 remove resource transaction over the same resource in one block + let txns = vec![ + Transaction::UserTransaction(remove_resource_txn(&sender, 18, vec![module.clone()])), + Transaction::UserTransaction(remove_resource_txn(&sender, 19, vec![module])), + ]; + let output = executor + .execute_transaction_block(txns) + .expect("Must execute transactions"); + assert_eq!( + output[0].status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + assert!(matches!( + output[1].status().status(), + // StatusCode::MISSING_DATA + Ok(KeptVMStatus::ExecutionFailure { .. }) + )); + for out in output { + executor.apply_write_set(out.write_set()); + } +} + +#[test] +fn borrow_after_move() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + // publish module with add and remove resource + let (module, txn) = add_module_txn(&sender, 10); + executor.execute_and_apply(txn); + + // remove resource fails given no resource were published + let rem_txn = remove_resource_txn(&sender, 11, vec![module.clone()]); + let output = executor.execute_transaction(rem_txn); + assert!(matches!( + output.status().status(), + // StatusCode::MISSING_DATA + Ok(KeptVMStatus::ExecutionFailure { .. }) + )); + executor.apply_write_set(output.write_set()); + + // publish resource + let add_txn = add_resource_txn(&sender, 12, vec![module.clone()]); + executor.execute_and_apply(add_txn); + + // borrow resource + let borrow_txn = borrow_resource_txn(&sender, 13, vec![module.clone()]); + executor.execute_and_apply(borrow_txn); + + // create a remove and a borrow resource transaction over the same resource in one block + let txns = vec![ + Transaction::UserTransaction(remove_resource_txn(&sender, 14, vec![module.clone()])), + Transaction::UserTransaction(borrow_resource_txn(&sender, 15, vec![module])), + ]; + let output = executor + .execute_transaction_block(txns) + .expect("Must execute transactions"); + assert_eq!( + output[0].status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + assert!(matches!( + output[1].status().status(), + // StatusCode::MISSING_DATA + Ok(KeptVMStatus::ExecutionFailure { .. }) + )); + for out in output { + executor.apply_write_set(out.write_set()); + } +} + +#[test] +fn change_after_move() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + // publish module with add and remove resource + let (module, txn) = add_module_txn(&sender, 10); + executor.execute_and_apply(txn); + + // remove resource fails given no resource were published + let rem_txn = remove_resource_txn(&sender, 11, vec![module.clone()]); + let output = executor.execute_transaction(rem_txn); + assert!(matches!( + output.status().status(), + // StatusCode::MISSING_DATA + Ok(KeptVMStatus::ExecutionFailure { .. }) + )); + executor.apply_write_set(output.write_set()); + + // publish resource + let add_txn = add_resource_txn(&sender, 12, vec![module.clone()]); + executor.execute_and_apply(add_txn); + + // borrow resource + let borrow_txn = borrow_resource_txn(&sender, 13, vec![module.clone()]); + executor.execute_and_apply(borrow_txn); + + // create a remove and a change resource transaction over the same resource in one block + let txns = vec![ + Transaction::UserTransaction(remove_resource_txn(&sender, 14, vec![module.clone()])), + Transaction::UserTransaction(change_resource_txn(&sender, 15, vec![module.clone()])), + ]; + let output = executor + .execute_transaction_block(txns) + .expect("Must execute transactions"); + assert_eq!( + output[0].status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + assert!(matches!( + output[1].status().status(), + // StatusCode::MISSING_DATA + Ok(KeptVMStatus::ExecutionFailure { .. }) + )); + for out in output { + executor.apply_write_set(out.write_set()); + } + + // borrow resource + let borrow_txn = borrow_resource_txn(&sender, 16, vec![module]); + let output = executor.execute_transaction(borrow_txn); + assert!(matches!( + output.status().status(), + // StatusCode::MISSING_DATA + Ok(KeptVMStatus::ExecutionFailure { .. }) + )); + executor.apply_write_set(output.write_set()); +} + +fn add_module_txn(sender: &AccountData, seq_num: u64) -> (CompiledModule, SignedTransaction) { + let module_code = format!( + " + module 0x{}.M {{ + import 0x1.Signer; + struct T1 has key {{ v: u64 }} + + public borrow_t1(account: &signer) acquires T1 {{ + let t1: &Self.T1; + label b0: + t1 = borrow_global(Signer.address_of(move(account))); + return; + }} + + public change_t1(account: &signer, v: u64) acquires T1 {{ + let t1: &mut Self.T1; + label b0: + t1 = borrow_global_mut(Signer.address_of(move(account))); + *&mut move(t1).T1::v = move(v); + return; + }} + + public remove_t1(account: &signer) acquires T1 {{ + let v: u64; + label b0: + T1 {{ v }} = move_from(Signer.address_of(move(account))); + return; + }} + + public publish_t1(account: &signer) {{ + label b0: + move_to(move(account), T1 {{ v: 3 }}); + return; + }} + }} + ", + sender.address(), + ); + + let compiler = Compiler { + deps: diem_framework_releases::current_modules().iter().collect(), + }; + let module = compiler + .into_compiled_module(module_code.as_str()) + .expect("Module compilation failed"); + let mut module_blob = vec![]; + module + .serialize(&mut module_blob) + .expect("Module must serialize"); + verify_module(&module).expect("Module must verify"); + ( + module, + sender + .account() + .transaction() + .module(Module::new(module_blob)) + .sequence_number(seq_num) + .sign(), + ) +} + +fn add_resource_txn( + sender: &AccountData, + seq_num: u64, + extra_deps: Vec, +) -> SignedTransaction { + let program = format!( + " + import 0x{}.M; + + main(account: signer) {{ + label b0: + M.publish_t1(&account); + return; + }} + ", + sender.address(), + ); + + let module = compile_script(&program, extra_deps); + sender + .account() + .transaction() + .script(module) + .sequence_number(seq_num) + .sign() +} + +fn remove_resource_txn( + sender: &AccountData, + seq_num: u64, + extra_deps: Vec, +) -> SignedTransaction { + let program = format!( + " + import 0x{}.M; + + main(account: signer) {{ + label b0: + M.remove_t1(&account); + return; + }} + ", + sender.address(), + ); + + let module = compile_script(&program, extra_deps); + sender + .account() + .transaction() + .script(module) + .sequence_number(seq_num) + .sign() +} + +fn borrow_resource_txn( + sender: &AccountData, + seq_num: u64, + extra_deps: Vec, +) -> SignedTransaction { + let program = format!( + " + import 0x{}.M; + + main(account: signer) {{ + label b0: + M.borrow_t1(&account); + return; + }} + ", + sender.address(), + ); + + let module = compile_script(&program, extra_deps); + sender + .account() + .transaction() + .script(module) + .sequence_number(seq_num) + .sign() +} + +fn change_resource_txn( + sender: &AccountData, + seq_num: u64, + extra_deps: Vec, +) -> SignedTransaction { + let program = format!( + " + import 0x{}.M; + + main(account: signer) {{ + label b0: + M.change_t1(&account, 20); + return; + }} + ", + sender.address(), + ); + + let module = compile_script(&program, extra_deps); + sender + .account() + .transaction() + .script(module) + .sequence_number(seq_num) + .sign() +} diff --git a/vm/e2e-testsuite/src/tests/emergency_admin_script.rs b/vm/e2e-testsuite/src/tests/emergency_admin_script.rs new file mode 100644 index 0000000000..82f6fff742 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/emergency_admin_script.rs @@ -0,0 +1,267 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use diem_transaction_builder::stdlib::*; +use diem_types::{ + account_config::diem_root_address, + on_chain_config::{new_epoch_event_key, DIEM_MAX_KNOWN_VERSION}, + transaction::{Transaction, TransactionStatus}, + vm_status::KeptVMStatus, +}; +use diem_writeset_generator::{ + encode_custom_script, encode_halt_network_payload, encode_remove_validators_payload, +}; +use move_core_types::{ + value::{serialize_values, MoveValue}, + vm_status::StatusCode, +}; +use serde_json::json; +use starcoin_language_e2e_tests::{ + common_transactions::peer_to_peer_txn, test_with_different_versions, + versioning::CURRENT_RELEASE_VERSIONS, +}; + +#[test] +fn validator_batch_remove() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let diem_root_account = test_env.dr_account; + let validator_account_0 = executor.create_raw_account(); + let validator_account_1 = executor.create_raw_account(); + let operator_account = executor.create_raw_account(); + + // Add validator_0 + executor.execute_and_apply( + diem_root_account + .transaction() + .script(encode_create_validator_account_script( + 0, + *validator_account_0.address(), + validator_account_0.auth_key_prefix(), + b"validator_0".to_vec(), + )) + .sequence_number(test_env.dr_sequence_number) + .sign(), + ); + // Add operator + executor.execute_and_apply( + diem_root_account + .transaction() + .script(encode_create_validator_operator_account_script( + 0, + *operator_account.address(), + operator_account.auth_key_prefix(), + b"operator".to_vec(), + )) + .sequence_number(test_env.dr_sequence_number.checked_add(1).unwrap()) + .sign(), + ); + // validator_0 sets operator + executor.execute_and_apply( + validator_account_0 + .transaction() + .script(encode_set_validator_operator_script( + b"operator".to_vec(), + *operator_account.address(), + )) + .sequence_number(0) + .sign(), + ); + + executor.new_block(); + + // operator_accounts registers config + executor.execute_and_apply( + operator_account + .transaction() + .script(encode_register_validator_config_script( + *validator_account_0.address(), + [ + 0xd7, 0x5a, 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b, 0xfe, 0xd3, 0xc9, + 0x64, 0x07, 0x3a, 0x0e, 0xe1, 0x72, 0xf3, 0xda, 0xa6, 0x23, 0x25, 0xaf, 0x02, + 0x1a, 0x68, 0xf7, 0x07, 0x51, 0x1a, + ] + .to_vec(), + vec![254; 32], + vec![253; 32], + )) + .sequence_number(0) + .sign(), + ); + + // diem_root adds validator + executor.execute_and_apply( + diem_root_account + .transaction() + .script(encode_add_validator_and_reconfigure_script( + 2, + b"validator_0".to_vec(), + *validator_account_0.address(), + )) + .sequence_number(test_env.dr_sequence_number.checked_add(2).unwrap()) + .sign(), + ); + + // Add validator_1 + executor.new_block(); + executor.execute_and_apply( + diem_root_account + .transaction() + .script(encode_create_validator_account_script( + 0, + *validator_account_1.address(), + validator_account_1.auth_key_prefix(), + b"validator_1".to_vec(), + )) + .sequence_number(test_env.dr_sequence_number.checked_add(3).unwrap()) + .sign(), + ); + // validator_1 sets operator + executor.execute_and_apply( + validator_account_1 + .transaction() + .script(encode_set_validator_operator_script( + b"operator".to_vec(), + *operator_account.address(), + )) + .sequence_number(0) + .sign(), + ); + executor.new_block(); + + // operator sets the config for validator_account_1 + executor.execute_and_apply( + operator_account + .transaction() + .script(encode_register_validator_config_script( + *validator_account_1.address(), + [ + 0xd7, 0x5a, 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b, 0xfe, 0xd3, 0xc9, + 0x64, 0x07, 0x3a, 0x0e, 0xe1, 0x72, 0xf3, 0xda, 0xa6, 0x23, 0x25, 0xaf, 0x02, + 0x1a, 0x68, 0xf7, 0x07, 0x51, 0x1a, + ] + .to_vec(), + vec![254; 32], + vec![253; 32], + )) + .sequence_number(1) + .sign(), + ); + + // diem_root adds validator + executor.execute_and_apply( + diem_root_account + .transaction() + .script(encode_add_validator_and_reconfigure_script( + 3, + b"validator_1".to_vec(), + *validator_account_1.address(), + )) + .sequence_number(test_env.dr_sequence_number.checked_add(4).unwrap()) + .sign(), + ); + + let txn1 = Transaction::GenesisTransaction(encode_remove_validators_payload(vec![ + *validator_account_0.address(), + *validator_account_1.address(), + ])); + + let txn2 = Transaction::GenesisTransaction(encode_custom_script( + "remove_validators.move", + &json!({ "addresses": [validator_account_0.address().to_string(), validator_account_1.address().to_string()]}), + Some(diem_root_address()), + )); + + assert_eq!(txn1, txn2); + // Remove two newly added validators. + executor.new_block(); + let output = executor + .execute_transaction_block(vec![txn1]) + .unwrap() + .pop() + .unwrap(); + assert!(output + .events() + .iter() + .any(|event| *event.key() == new_epoch_event_key())); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + + executor.apply_write_set(output.write_set()); + + // Make sure both validators are removed from the validator set. + assert!(executor + .try_exec( + "DiemSystem", + "remove_validator", + vec![], + serialize_values(&vec![ + MoveValue::Signer(*diem_root_account.address()), + MoveValue::Address(*validator_account_0.address()) + ]), + ) + .is_err()); + assert!(executor + .try_exec( + "DiemSystem", + "remove_validator", + vec![], + serialize_values(&vec![ + MoveValue::Signer(*diem_root_account.address()), + MoveValue::Address(*validator_account_1.address()) + ]), + ) + .is_err()); + } + } +} + +#[test] +fn halt_network() { + // This can only run on versions >= 2 since + // `DiemTransactionPublishingOption::halt_all_transactions` is not available in version 1. + test_with_different_versions! {2..=DIEM_MAX_KNOWN_VERSION.major, |test_env| { + let mut executor = test_env.executor; + let diem_root_account = test_env.dr_account; + let sender = executor.create_raw_account_data(1_000_000, 10); + let receiver = executor.create_raw_account_data(100_000, 10); + executor.add_account_data(&sender); + executor.add_account_data(&receiver); + + executor.new_block(); + let output = executor + .execute_transaction_block(vec![Transaction::GenesisTransaction( + encode_halt_network_payload(), + )]) + .unwrap() + .pop() + .unwrap(); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + + executor.apply_write_set(output.write_set()); + + let txn = peer_to_peer_txn(sender.account(), receiver.account(), 10, 1); + // Regular transactions like p2p are no longer allowed. + let output = executor.execute_transaction(txn); + assert_eq!( + output.status(), + &TransactionStatus::Discard(StatusCode::UNKNOWN_SCRIPT) + ); + + let auth_key = diem_root_account.auth_key(); + // DiemRoot can still send transaction + executor.execute_and_apply( + diem_root_account + .transaction() + .script(encode_rotate_authentication_key_script(auth_key)) + .sequence_number(test_env.dr_sequence_number) + .sign(), + ); + } + } +} diff --git a/vm/e2e-testsuite/src/tests/execution_strategies.rs b/vm/e2e-testsuite/src/tests/execution_strategies.rs new file mode 100644 index 0000000000..1e6d081ae7 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/execution_strategies.rs @@ -0,0 +1,120 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use diem_types::{account_config, transaction::SignedTransaction, vm_status::VMStatus}; +use starcoin_language_e2e_tests::{ + account::Account, + common_transactions::create_account_txn, + execution_strategies::{ + basic_strategy::BasicExecutor, + guided_strategy::{ + AnnotatedTransaction, GuidedExecutor, PartitionedGuidedStrategy, + UnPartitionedGuidedStrategy, + }, + multi_strategy::MultiExecutor, + random_strategy::RandomExecutor, + types::Executor, + }, +}; + +fn txn(seq_num: u64) -> SignedTransaction { + let account = Account::new(); + let diem_root = Account::new_diem_root(); + create_account_txn( + &diem_root, + &account, + seq_num + 1, + 0, + account_config::xus_tag(), + ) +} + +#[test] +fn test_execution_strategies() { + { + println!("==========================================================================="); + println!("TESTING BASIC STRATEGY"); + println!("==========================================================================="); + let big_block = (0..10).map(txn).collect(); + let mut exec = BasicExecutor::new(); + exec.execute_block(big_block).unwrap(); + } + + { + println!("==========================================================================="); + println!("TESTING RANDOM STRATEGY"); + println!("==========================================================================="); + let big_block = (0..10).map(txn).collect(); + let mut exec = RandomExecutor::from_os_rng(); + exec.execute_block(big_block).unwrap(); + } + + { + println!("==========================================================================="); + println!("TESTING GUIDED STRATEGY"); + println!("==========================================================================="); + let mut block1: Vec<_> = (0..10) + .map(|i| AnnotatedTransaction::Txn(Box::new(txn(i)))) + .collect(); + block1.push(AnnotatedTransaction::Block); + let mut block = (0..5) + .map(|i| AnnotatedTransaction::Txn(Box::new(txn(i + 10)))) + .collect(); + block1.append(&mut block); + block1.push(AnnotatedTransaction::Block); + let mut block: Vec<_> = (0..7) + .map(|i| AnnotatedTransaction::Txn(Box::new(txn(i + 15)))) + .collect(); + block1.append(&mut block); + block1.push(AnnotatedTransaction::Block); + let mut block = (0..20) + .map(|i| AnnotatedTransaction::Txn(Box::new(txn(i + 22)))) + .collect(); + block1.append(&mut block); + + let mut exec = GuidedExecutor::new(PartitionedGuidedStrategy); + exec.execute_block(block1).unwrap(); + } + + { + println!("==========================================================================="); + println!("TESTING COMPOSED STRATEGY 1"); + println!("==========================================================================="); + let mut block1: Vec<_> = (0..10) + .map(|i| AnnotatedTransaction::Txn(Box::new(txn(i)))) + .collect(); + block1.push(AnnotatedTransaction::Block); + let mut block = (0..5) + .map(|i| AnnotatedTransaction::Txn(Box::new(txn(i + 10)))) + .collect(); + block1.append(&mut block); + block1.push(AnnotatedTransaction::Block); + let mut block: Vec<_> = (0..7) + .map(|i| AnnotatedTransaction::Txn(Box::new(txn(i + 15)))) + .collect(); + block1.append(&mut block); + block1.push(AnnotatedTransaction::Block); + let mut block = (0..20) + .map(|i| AnnotatedTransaction::Txn(Box::new(txn(i + 22)))) + .collect(); + block1.append(&mut block); + + let mut exec = MultiExecutor::::new(); + exec.add_executor(GuidedExecutor::new(PartitionedGuidedStrategy)); + exec.add_executor(GuidedExecutor::new(UnPartitionedGuidedStrategy)); + exec.execute_block(block1).unwrap(); + } + + { + println!("==========================================================================="); + println!("TESTING COMPOSED STRATEGY 2"); + println!("==========================================================================="); + let block = (0..10).map(txn).collect(); + + let mut exec = MultiExecutor::::new(); + exec.add_executor(RandomExecutor::from_os_rng()); + exec.add_executor(RandomExecutor::from_os_rng()); + exec.add_executor(RandomExecutor::from_os_rng()); + exec.execute_block(block).unwrap(); + } +} diff --git a/vm/e2e-testsuite/src/tests/experimental.rs b/vm/e2e-testsuite/src/tests/experimental.rs new file mode 100644 index 0000000000..ed2e9a93f7 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/experimental.rs @@ -0,0 +1,65 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use diem_transaction_builder::experimental_stdlib::encode_create_account_script_function; +use diem_types::vm_status::StatusCode; +use starcoin_language_e2e_tests::{ + account::Account, current_function_name, executor::FakeExecutor, +}; + +// Make sure we can start the experimental genesis +#[test] +fn experimental_genesis_runs() { + FakeExecutor::from_experimental_genesis(); +} + +// Make sure that we can execute transactions with the experimental genesis +#[test] +fn experimental_genesis_execute_txn_successful() { + let mut executor = FakeExecutor::from_experimental_genesis(); + executor.set_golden_file(current_function_name!()); + let new_account = executor.create_raw_account(); + let new_new_account = executor.create_raw_account(); + let dr_account = Account::new_diem_root(); + let txn = dr_account + .transaction() + .payload(encode_create_account_script_function( + *new_account.address(), + new_account.auth_key_prefix(), + )) + .sequence_number(0) + .sign(); + executor.execute_and_apply(txn); + + // Other accounts can create accounts, no role checks + let txn = new_account + .transaction() + .payload(encode_create_account_script_function( + *new_new_account.address(), + new_new_account.auth_key_prefix(), + )) + .sequence_number(0) + .sign(); + executor.execute_and_apply(txn); +} + +// Make sure that we can handle prologue errors from the non-DPN account module +#[test] +fn experimental_genesis_execute_txn_non_existent_sender() { + let mut executor = FakeExecutor::from_experimental_genesis(); + executor.set_golden_file(current_function_name!()); + let new_account = executor.create_raw_account(); + let txn = new_account + .transaction() + .payload(encode_create_account_script_function( + *new_account.address(), + new_account.auth_key_prefix(), + )) + .sequence_number(0) + .sign(); + let output = &executor.execute_transaction(txn); + assert_eq!( + output.status().status(), + Err(StatusCode::SENDING_ACCOUNT_DOES_NOT_EXIST), + ); +} diff --git a/vm/e2e-testsuite/src/tests/failed_transaction_tests.rs b/vm/e2e-testsuite/src/tests/failed_transaction_tests.rs new file mode 100644 index 0000000000..4c15cc877a --- /dev/null +++ b/vm/e2e-testsuite/src/tests/failed_transaction_tests.rs @@ -0,0 +1,101 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use diem_state_view::StateView; +use diem_types::vm_status::{KeptVMStatus, StatusCode, VMStatus}; +use diem_vm::{ + data_cache::StateViewCache, logging::AdapterLogSchema, + transaction_metadata::TransactionMetadata, DiemVM, +}; +use move_core_types::gas_schedule::{GasAlgebra, GasPrice, GasUnits}; +use move_vm_types::gas_schedule::{zero_cost_schedule, GasStatus}; +use starcoin_language_e2e_tests::{ + account, common_transactions::peer_to_peer_txn, test_with_different_versions, + versioning::CURRENT_RELEASE_VERSIONS, +}; + +#[test] +fn failed_transaction_cleanup_test() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + let log_context = AdapterLogSchema::new(executor.get_state_view().id(), 0); + let diem_vm = DiemVM::new(executor.get_state_view()); + let data_cache = StateViewCache::new(executor.get_state_view()); + + let txn_data = TransactionMetadata { + sender: *sender.address(), + max_gas_amount: GasUnits::new(100_000), + gas_unit_price: GasPrice::new(0), + sequence_number: 10, + ..Default::default() + }; + + let gas_schedule = zero_cost_schedule(); + let mut gas_status = GasStatus::new(&gas_schedule, GasUnits::new(10_000)); + + // TYPE_MISMATCH should be kept and charged. + let out1 = diem_vm.failed_transaction_cleanup( + VMStatus::Error(StatusCode::TYPE_MISMATCH), + &mut gas_status, + &txn_data, + &data_cache, + &account::xus_currency_code(), + &log_context, + ); + assert!(!out1.write_set().is_empty()); + assert_eq!(out1.gas_used(), 90_000); + assert!(!out1.status().is_discarded()); + assert_eq!( + out1.status().status(), + // StatusCode::TYPE_MISMATCH + Ok(KeptVMStatus::MiscellaneousError) + ); + + // Invariant violations should be discarded and not charged. + let out2 = diem_vm.failed_transaction_cleanup( + VMStatus::Error(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR), + &mut gas_status, + &txn_data, + &data_cache, + &account::xus_currency_code(), + &log_context, + ); + assert!(out2.write_set().is_empty()); + assert!(out2.gas_used() == 0); + assert!(out2.status().is_discarded()); + assert_eq!( + out2.status().status(), + Err(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) + ); + } + } +} + +#[test] +fn non_existent_sender() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let sequence_number = 0; + let sender = executor.create_raw_account(); + let receiver = executor.create_raw_account_data(100_000, sequence_number); + executor.add_account_data(&receiver); + + let transfer_amount = 10; + let txn = peer_to_peer_txn( + &sender, + receiver.account(), + sequence_number, + transfer_amount, + ); + + let output = &executor.execute_transaction(txn); + assert_eq!( + output.status().status(), + Err(StatusCode::SENDING_ACCOUNT_DOES_NOT_EXIST), + ); + } + } +} diff --git a/vm/e2e-testsuite/src/tests/genesis.rs b/vm/e2e-testsuite/src/tests/genesis.rs new file mode 100644 index 0000000000..f0249bae56 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/genesis.rs @@ -0,0 +1,42 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use diem_types::transaction::{Transaction, TransactionStatus, WriteSetPayload}; +use starcoin_language_e2e_tests::{ + common_transactions::peer_to_peer_txn, data_store::GENESIS_CHANGE_SET, executor::FakeExecutor, +}; + +#[test] +fn no_deletion_in_genesis() { + let genesis = GENESIS_CHANGE_SET.clone(); + assert!(!genesis.write_set().iter().any(|(_, op)| op.is_deletion())) +} + +#[test] +fn execute_genesis_write_set() { + let executor = FakeExecutor::no_genesis(); + let txn = Transaction::GenesisTransaction(WriteSetPayload::Direct(GENESIS_CHANGE_SET.clone())); + let mut output = executor.execute_transaction_block(vec![txn]).unwrap(); + + // Executing the genesis transaction should succeed + assert_eq!(output.len(), 1); + assert!(!output.pop().unwrap().status().is_discarded()) +} + +#[test] +fn execute_genesis_and_drop_other_transaction() { + let mut executor = FakeExecutor::no_genesis(); + let txn = Transaction::GenesisTransaction(WriteSetPayload::Direct(GENESIS_CHANGE_SET.clone())); + + let sender = executor.create_raw_account_data(1_000_000, 10); + let receiver = executor.create_raw_account_data(100_000, 10); + let txn2 = peer_to_peer_txn(sender.account(), receiver.account(), 11, 1000); + + let mut output = executor + .execute_transaction_block(vec![txn, Transaction::UserTransaction(txn2)]) + .unwrap(); + + // Transaction that comes after genesis should be dropped. + assert_eq!(output.len(), 2); + assert_eq!(output.pop().unwrap().status(), &TransactionStatus::Retry) +} diff --git a/vm/e2e-testsuite/src/tests/genesis_initializations.rs b/vm/e2e-testsuite/src/tests/genesis_initializations.rs new file mode 100644 index 0000000000..247867dfcf --- /dev/null +++ b/vm/e2e-testsuite/src/tests/genesis_initializations.rs @@ -0,0 +1,190 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use diem_types::account_config; +use move_core_types::{ + account_address::AccountAddress, + value::{serialize_values, MoveValue}, +}; +use starcoin_language_e2e_tests::executor::FakeExecutor; + +#[test] +fn test_diem_initialize() { + let mut executor = FakeExecutor::stdlib_only_genesis(); + + // DR doesn't have role yet, so role check will fail + let output = executor.try_exec( + "Diem", + "initialize", + vec![], + serialize_values(&vec![ + MoveValue::Signer(account_config::diem_root_address()), + ]), + ); + assert_eq!(output.unwrap_err().move_abort_code(), Some(5)); + + // Grant the DR role + executor.exec( + "Roles", + "grant_diem_root_role", + vec![], + serialize_values(&vec![ + MoveValue::Signer(account_config::diem_root_address()), + ]), + ); + + // Now initialize, it should all succeed. + executor.exec( + "Diem", + "initialize", + vec![], + serialize_values(&vec![ + MoveValue::Signer(account_config::diem_root_address()), + ]), + ); + + // Second time you try though you'll get an already published error with EMODIFY_CAPABILITY + // reason. + let output = executor.try_exec( + "Diem", + "initialize", + vec![], + serialize_values(&vec![ + MoveValue::Signer(account_config::diem_root_address()), + ]), + ); + + assert_eq!(output.unwrap_err().move_abort_code(), Some(262)); +} + +#[test] +fn test_diem_initialize_tc_account() { + let mut executor = FakeExecutor::stdlib_only_genesis(); + + // DR doesn't have role yet, so role check will fail + let output = executor.try_exec( + "Diem", + "initialize", + vec![], + serialize_values(&vec![ + MoveValue::Signer(account_config::diem_root_address()), + ]), + ); + assert_eq!(output.unwrap_err().move_abort_code(), Some(5)); + + // Grant the DR role + executor.exec( + "Roles", + "grant_diem_root_role", + vec![], + serialize_values(&vec![ + MoveValue::Signer(account_config::diem_root_address()), + ]), + ); + + // Grant the TC role + executor.exec( + "Roles", + "grant_treasury_compliance_role", + vec![], + serialize_values(&vec![ + MoveValue::Signer(account_config::treasury_compliance_account_address()), + MoveValue::Signer(account_config::diem_root_address()), + ]), + ); + + // Try to initialize, invalid sender so role check will fail + let output = executor.try_exec( + "Diem", + "initialize", + vec![], + serialize_values(&vec![MoveValue::Signer( + account_config::treasury_compliance_account_address(), + )]), + ); + + assert_eq!(output.unwrap_err().move_abort_code(), Some(2)); + + // Now initialize, it should all succeed. + executor.exec( + "Diem", + "initialize", + vec![], + serialize_values(&vec![ + MoveValue::Signer(account_config::diem_root_address()), + ]), + ); + + // Second time you try though you'll get an already published error with EMODIFY_CAPABILITY + // reason. + let output = executor.try_exec( + "Diem", + "initialize", + vec![], + serialize_values(&vec![MoveValue::Signer( + account_config::treasury_compliance_account_address(), + )]), + ); + + assert_eq!(output.unwrap_err().move_abort_code(), Some(2)); +} + +#[test] +fn test_diem_timestamp_time_has_started() { + let mut executor = FakeExecutor::stdlib_only_genesis(); + let account_address = AccountAddress::random(); + + // Invalid address used to call `DiemTimestamp::set_time_has_started` + let output = executor.try_exec( + "DiemTimestamp", + "set_time_has_started", + vec![], + serialize_values(&vec![MoveValue::Signer(account_address)]), + ); + assert_eq!(output.unwrap_err().move_abort_code(), Some(2)); + + executor.exec( + "DiemTimestamp", + "set_time_has_started", + vec![], + serialize_values(&vec![ + MoveValue::Signer(account_config::diem_root_address()), + ]), + ); + + let output = executor.try_exec( + "DiemTimestamp", + "set_time_has_started", + vec![], + serialize_values(&vec![ + MoveValue::Signer(account_config::diem_root_address()), + ]), + ); + + assert_eq!(output.unwrap_err().move_abort_code(), Some(1)); +} + +#[test] +fn test_diem_block_double_init() { + let mut executor = FakeExecutor::stdlib_only_genesis(); + + executor.exec( + "DiemBlock", + "initialize_block_metadata", + vec![], + serialize_values(&vec![ + MoveValue::Signer(account_config::diem_root_address()), + ]), + ); + + let output = executor.try_exec( + "DiemBlock", + "initialize_block_metadata", + vec![], + serialize_values(&vec![ + MoveValue::Signer(account_config::diem_root_address()), + ]), + ); + + assert_eq!(output.unwrap_err().move_abort_code(), Some(6)); +} diff --git a/vm/e2e-testsuite/src/tests/mint.rs b/vm/e2e-testsuite/src/tests/mint.rs new file mode 100644 index 0000000000..d120eb8845 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/mint.rs @@ -0,0 +1,202 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use diem_transaction_builder::stdlib::*; +use diem_types::{ + account_config, + transaction::TransactionStatus, + vm_status::{known_locations, KeptVMStatus}, +}; +use starcoin_language_e2e_tests::{ + account, gas_costs::TXN_RESERVED, test_with_different_versions, + versioning::CURRENT_RELEASE_VERSIONS, +}; + +#[test] +fn tiered_mint_designated_dealer() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + let blessed = test_env.tc_account; + + // account to represent designated dealer + let dd = executor.create_raw_account(); + executor.execute_and_apply( + blessed + .transaction() + .script(encode_create_designated_dealer_script( + account_config::xus_tag(), + 0, + *dd.address(), + dd.auth_key_prefix(), + vec![], + false, // add_all_currencies + )) + .sequence_number(test_env.tc_sequence_number) + .sign(), + ); + let mint_amount_one = 1_000; + let tier_index = 0; + executor.execute_and_apply( + blessed + .transaction() + .script(encode_tiered_mint_script( + account_config::xus_tag(), + 1, + *dd.address(), + mint_amount_one, + tier_index, + )) + .sequence_number(test_env.tc_sequence_number.checked_add(1).unwrap()) + .sign(), + ); + let dd_post_mint = executor + .read_account_resource(&dd) + .expect("receiver must exist"); + let dd_balance = executor + .read_balance_resource(&dd, account::xus_currency_code()) + .expect("receiver balance must exist"); + assert_eq!(mint_amount_one, dd_balance.coin()); + assert_eq!(0, dd_post_mint.sequence_number()); + + // -------------- + let mint_amount_two = 5_000_000; + let tier_index = 3; + executor.execute_and_apply( + blessed + .transaction() + .script(encode_tiered_mint_script( + account_config::xus_tag(), + 2, + *dd.address(), + mint_amount_two, + tier_index, + )) + .sequence_number(test_env.tc_sequence_number.checked_add(2).unwrap()) + .sign(), + ); + let dd_balance = executor + .read_balance_resource(&dd, account::xus_currency_code()) + .expect("receiver balance must exist"); + assert_eq!(mint_amount_one + mint_amount_two, dd_balance.coin()); + } + } +} + +#[test] +fn mint_to_existing_not_dd() { + // We can't run mint test on terraform genesis as we don't have the private key to sign the + // mint transaction. + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + let blessed = test_env.tc_account; + + // create and publish a sender with 1_000_000 coins + let receiver = executor.create_raw_account(); + + executor.execute_and_apply( + blessed + .transaction() + .script(encode_create_parent_vasp_account_script( + account_config::xus_tag(), + 0, + *receiver.address(), + receiver.auth_key_prefix(), + vec![], + false, + )) + .sequence_number(test_env.tc_sequence_number) + .sign(), + ); + + let mint_amount = 1_000; + let output = executor.execute_transaction( + blessed + .transaction() + .script(encode_tiered_mint_script( + account_config::xus_tag(), + 0, + *receiver.address(), + mint_amount, + 4, + )) + .sequence_number(test_env.tc_sequence_number.checked_add(1).unwrap()) + .sign(), + ); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::MoveAbort( + known_locations::designated_dealer_module_abort(), + 5 + )), + ); + } + } +} + +#[test] +fn mint_to_new_account() { + // We can't run mint test on terraform genesis as we don't have the private key to sign the + // mint transaction. + + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + let tc = test_env.tc_account; + + // create and publish a sender with TXN_RESERVED coins + let new_account = executor.create_raw_account(); + + let mint_amount = TXN_RESERVED; + let output = executor.execute_transaction( + tc.transaction() + .script(encode_tiered_mint_script( + account_config::xus_tag(), + 0, + *new_account.address(), + mint_amount, + 4, + )) + .sequence_number(0) + .sign(), + ); + + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::MoveAbort( + known_locations::designated_dealer_module_abort(), + 5 + )), + ); + } + } +} + +#[test] +fn tiered_update_exchange_rate() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + let blessed = test_env.tc_account; + + // set xus rate to 1.23 XUS + executor.execute_and_apply( + blessed + .transaction() + .script(encode_update_exchange_rate_script( + account_config::xus_tag(), + 0, + 123, + 100, + )) + .sequence_number(test_env.tc_sequence_number) + .sign(), + ); + let post_update = executor + .read_account_resource(&blessed) + .expect("blessed executed txn"); + assert_eq!(1, post_update.sequence_number()); + } + } +} diff --git a/vm/e2e-testsuite/src/tests/mod.rs b/vm/e2e-testsuite/src/tests/mod.rs new file mode 100644 index 0000000000..91c856e6a3 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/mod.rs @@ -0,0 +1,41 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +//! Test module. +//! +//! Add new test modules to this list. +//! +//! This is not in a top-level tests directory because each file there gets compiled into a +//! separate binary. The linker ends up repeating a lot of work for each binary to not much +//! benefit. + +mod account_limits; +mod account_universe; +mod admin_script; +mod create_account; +mod crsn; +mod data_store; +mod emergency_admin_script; +mod execution_strategies; +mod experimental; +mod failed_transaction_tests; +mod genesis; +mod genesis_initializations; +mod mint; +mod module_publishing; +mod multi_agent; +mod on_chain_configs; +mod parallel_execution; +mod peer_to_peer; +mod preburn_queue; +mod rotate_key; +mod script_functions; +mod scripts; +mod transaction_builder; +mod transaction_fees; +mod transaction_fuzzer; +mod validator_set_management; +mod vasps; +mod verify_txn; +mod write_set; +mod writeset_builder; diff --git a/vm/e2e-testsuite/src/tests/module_publishing.rs b/vm/e2e-testsuite/src/tests/module_publishing.rs new file mode 100644 index 0000000000..d8fe81d901 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/module_publishing.rs @@ -0,0 +1,452 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use diem_types::{ + account_config::{self}, + on_chain_config::VMPublishingOption, + transaction::TransactionStatus, + vm_status::{KeptVMStatus, StatusCode}, +}; +use starcoin_language_e2e_tests::{ + account::Account, assert_prologue_parity, compile::compile_module, current_function_name, + executor::FakeExecutor, transaction_status_eq, +}; + +// A module with an address different from the sender's address should be rejected +#[test] +fn bad_module_address() { + let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + executor.set_golden_file(current_function_name!()); + + // create a transaction trying to publish a new module. + let account1 = executor.create_raw_account_data(1_000_000, 10); + let account2 = executor.create_raw_account_data(1_000_000, 10); + + executor.add_account_data(&account1); + executor.add_account_data(&account2); + + let program = format!( + " + module 0x{}.M {{ + }} + ", + account1.address() + ); + + // compile with account 1's address + let compiled_module = compile_module(&program).1; + // send with account 2's address + let txn = account2 + .account() + .transaction() + .module(compiled_module) + .sequence_number(10) + .gas_unit_price(1) + .sign(); + + // TODO: This is not verified for now. + // verify and fail because the addresses don't match + // let vm_status = executor.verify_transaction(txn.clone()).status().unwrap(); + // assert!(vm_status.is(StatusType::Verification)); + // assert!(vm_status.major_status == StatusCode::MODULE_ADDRESS_DOES_NOT_MATCH_SENDER); + + // execute and fail for the same reason + let output = executor.execute_transaction(txn); + match output.status() { + TransactionStatus::Keep(status) => { + assert!(status == &KeptVMStatus::MiscellaneousError); + // assert!(status.status_code() == StatusCode::MODULE_ADDRESS_DOES_NOT_MATCH_SENDER); + } + vm_status => panic!("Unexpected verification status: {:?}", vm_status), + }; +} + +macro_rules! module_republish_test { + ($name:ident, $prog1:literal, $prog2:literal, $result:ident) => { + #[test] + fn $name() { + let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + executor.set_golden_file(current_function_name!()); + + let sequence_number = 2; + let account = executor.create_raw_account_data(1_000_000, sequence_number); + executor.add_account_data(&account); + + let program1 = String::from($prog1).replace("##ADDRESS##", &account.address().to_hex()); + let compiled_module1 = compile_module(&program1).1; + + let txn1 = account + .account() + .transaction() + .module(compiled_module1.clone()) + .sequence_number(sequence_number) + .sign(); + + let program2 = String::from($prog2).replace("##ADDRESS##", &account.address().to_hex()); + let compiled_module2 = compile_module(&program2).1; + + let txn2 = account + .account() + .transaction() + .module(compiled_module2) + .sequence_number(sequence_number + 1) + .sign(); + + let output1 = executor.execute_transaction(txn1); + executor.apply_write_set(output1.write_set()); + // first tx should allways succeed + assert!(transaction_status_eq( + &output1.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed), + )); + + let output2 = executor.execute_transaction(txn2); + // second tx should yield the expected result + assert!(transaction_status_eq( + &output2.status(), + &TransactionStatus::Keep(KeptVMStatus::$result), + )); + } + }; +} + +// Publishing a module named M under the same address twice is OK (a module is self-compatible) +module_republish_test!( + duplicate_module, + " + module 0x##ADDRESS##.M { + struct T { f: u64 } + public f() { label b0: return; } + } + ", + " + module 0x##ADDRESS##.M { + struct T { f: u64 } + public f() { label b0: return; } + } + ", + Executed +); + +// Republishing a module named M under the same address with a superset of the structs is OK +module_republish_test!( + layout_compatible_module, + " + module 0x##ADDRESS##.M { + } + ", + " + module 0x##ADDRESS##.M { + struct T { f: u64 } + } + ", + Executed +); + +// Republishing a module named M under the same address with a superset of public functions is OK +module_republish_test!( + linking_compatible_module, + " + module 0x##ADDRESS##.M { + } + ", + " + module 0x##ADDRESS##.M { + public f() { label b0: return; } + } + ", + Executed +); + +// Republishing a module named M under the same address that breaks data layout should be rejected +module_republish_test!( + layout_incompatible_module_with_new_field, + " + module 0x##ADDRESS##.M { + struct T { f: u64 } + } + ", + " + module 0x##ADDRESS##.M { + struct T { f: u64, g: bool } + } + ", + MiscellaneousError +); + +module_republish_test!( + layout_incompatible_module_with_changed_field, + " + module 0x##ADDRESS##.M { + struct T { f: u64 } + } + ", + " + module 0x##ADDRESS##.M { + struct T { f: bool } + } + ", + MiscellaneousError +); + +module_republish_test!( + layout_incompatible_module_with_removed_field, + " + module 0x##ADDRESS##.M { + struct T { f: u64 } + } + ", + " + module 0x##ADDRESS##.M { + struct T {} + } + ", + MiscellaneousError +); + +module_republish_test!( + layout_incompatible_module_with_removed_struct, + " + module 0x##ADDRESS##.M { + struct T { f: u64 } + } + ", + " + module 0x##ADDRESS##.M { + } + ", + MiscellaneousError +); + +// Republishing a module named M under the same address that breaks linking should be rejected +module_republish_test!( + linking_incompatible_module_with_added_param, + " + module 0x##ADDRESS##.M { + public f() { label b0: return; } + } + ", + " + module 0x##ADDRESS##.M { + public f(_a: u64) { label b0: return; } + } + ", + MiscellaneousError +); + +module_republish_test!( + linking_incompatible_module_with_changed_param, + " + module 0x##ADDRESS##.M { + public f(_a: u64) { label b0: return; } + } + ", + " + module 0x##ADDRESS##.M { + public f(_a: bool) { label b0: return; } + } + ", + MiscellaneousError +); + +module_republish_test!( + linking_incompatible_module_with_removed_pub_fn, + " + module 0x##ADDRESS##.M { + public f() { label b0: return; } + } + ", + " + module 0x##ADDRESS##.M { + } + ", + MiscellaneousError +); + +#[test] +pub fn test_publishing_no_modules_non_allowlist_script() { + // create a FakeExecutor with a genesis from file + let mut executor = + FakeExecutor::from_genesis_with_options(VMPublishingOption::custom_scripts()); + executor.set_golden_file(current_function_name!()); + + // create a transaction trying to publish a new module. + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + let program = format!( + " + module 0x{}.M {{ + }} + ", + sender.address(), + ); + + let random_module = compile_module(&program).1; + let txn = sender + .account() + .transaction() + .module(random_module) + .sequence_number(10) + .gas_unit_price(1) + .sign(); + + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::INVALID_MODULE_PUBLISHER + ); +} + +#[test] +pub fn test_publishing_no_modules_non_allowlist_script_proper_sender() { + // create a FakeExecutor with a genesis from file + let mut executor = + FakeExecutor::from_genesis_with_options(VMPublishingOption::custom_scripts()); + executor.set_golden_file(current_function_name!()); + + // create a transaction trying to publish a new module. + let sender = Account::new_diem_root(); + + let program = String::from( + " + module 0x1.M { + } + ", + ); + + let random_module = compile_module(&program).1; + let txn = sender + .transaction() + .module(random_module) + .sequence_number(0) + .sign(); + assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!( + executor.execute_transaction(txn).status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); +} + +#[test] +pub fn test_publishing_no_modules_proper_sender() { + // create a FakeExecutor with a genesis from file + let mut executor = FakeExecutor::allowlist_genesis(); + executor.set_golden_file(current_function_name!()); + + // create a transaction trying to publish a new module. + let sender = Account::new_diem_root(); + + let program = String::from( + " + module 0x1.M { + } + ", + ); + + let random_script = compile_module(&program).1; + let txn = sender + .transaction() + .module(random_script) + .sequence_number(0) + .sign(); + assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!( + executor.execute_transaction(txn).status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); +} + +#[test] +pub fn test_publishing_no_modules_core_code_sender() { + // create a FakeExecutor with a genesis from file + let mut executor = FakeExecutor::allowlist_genesis(); + executor.set_golden_file(current_function_name!()); + + // create a transaction trying to publish a new module. + let sender = Account::new_genesis_account(account_config::CORE_CODE_ADDRESS); + + let program = String::from( + " + module 0x1.M { + } + ", + ); + + let random_script = compile_module(&program).1; + let txn = sender + .transaction() + .module(random_script) + .sequence_number(1) + .sign(); + // Doesn't work because the core code address doesn't exist + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::INVALID_MODULE_PUBLISHER + ); +} + +#[test] +pub fn test_publishing_no_modules_invalid_sender() { + // create a FakeExecutor with a genesis from file + let mut executor = FakeExecutor::allowlist_genesis(); + executor.set_golden_file(current_function_name!()); + + // create a transaction trying to publish a new module. + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + let program = format!( + " + module 0x{}.M {{ + }} + ", + sender.address(), + ); + + let random_script = compile_module(&program).1; + let txn = sender + .account() + .transaction() + .module(random_script) + .sequence_number(10) + .sign(); + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::INVALID_MODULE_PUBLISHER + ); +} + +#[test] +pub fn test_publishing_allow_modules() { + // create a FakeExecutor with a genesis from file + let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + executor.set_golden_file(current_function_name!()); + + // create a transaction trying to publish a new module. + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + let program = format!( + " + module 0x{}.M {{ + }} + ", + sender.address(), + ); + + let random_script = compile_module(&program).1; + let txn = sender + .account() + .transaction() + .module(random_script) + .sequence_number(10) + .sign(); + assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!( + executor.execute_transaction(txn).status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); +} diff --git a/vm/e2e-testsuite/src/tests/multi_agent.rs b/vm/e2e-testsuite/src/tests/multi_agent.rs new file mode 100644 index 0000000000..93522c26cc --- /dev/null +++ b/vm/e2e-testsuite/src/tests/multi_agent.rs @@ -0,0 +1,249 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +//! Tests for multi-agent transactions. + +use diem_transaction_builder::stdlib::*; +use diem_types::{ + account_config, test_helpers::transaction_test_helpers, transaction::TransactionStatus, + vm_status::KeptVMStatus, +}; +use starcoin_language_e2e_tests::{ + account::{self, xdx_currency_code, xus_currency_code, Account}, + common_transactions::{ + multi_agent_mint_txn, multi_agent_p2p_txn, multi_agent_swap_script, multi_agent_swap_txn, + }, + current_function_name, + executor::FakeExecutor, +}; + +#[test] +fn multi_agent_mint() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + + let tc = Account::new_blessed_tc(); + + // account to represent designated dealer + let dd = executor.create_raw_account(); + executor.execute_and_apply( + tc.transaction() + .script(encode_create_designated_dealer_script( + account_config::xus_tag(), + 0, + *dd.address(), + dd.auth_key_prefix(), + vec![], + false, // add_all_currencies + )) + .sequence_number(0) + .sign(), + ); + + // account to represent VASP + let vasp = executor.create_raw_account(); + executor.execute_and_apply( + tc.transaction() + .script(encode_create_parent_vasp_account_script( + account_config::xus_tag(), + 0, + *vasp.address(), + vasp.auth_key_prefix(), + vec![], + false, // add_all_currencies + )) + .sequence_number(1) + .sign(), + ); + + let mint_amount = 1_000; + let tier_index = 0; + let txn = multi_agent_mint_txn(&tc, &dd, &vasp, 2, mint_amount, tier_index); + + // execute transaction + let output = executor.execute_transaction(txn); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + + executor.apply_write_set(output.write_set()); + + let updated_tc = executor.read_account_resource(&tc).expect("tc must exist"); + let updated_dd = executor.read_account_resource(&dd).expect("dd must exist"); + let updated_vasp = executor + .read_account_resource(&vasp) + .expect("vasp must exist"); + let updated_dd_balance = executor + .read_balance_resource(&dd, account::xus_currency_code()) + .expect("dd balance must exist"); + let updated_vasp_balance = executor + .read_balance_resource(&vasp, account::xus_currency_code()) + .expect("vasp balance must exist"); + assert_eq!(0, updated_dd_balance.coin()); + assert_eq!(mint_amount, updated_vasp_balance.coin()); + assert_eq!(3, updated_tc.sequence_number()); + assert_eq!(0, updated_dd.sequence_number()); + assert_eq!(0, updated_vasp.sequence_number()); + assert_eq!(1, updated_dd.sent_events().count()); + assert_eq!(1, updated_vasp.received_events().count()); +} + +#[test] +fn multi_agent_swap() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + // create and publish a sender with 1_000_010 XUS coins + // and a secondary signer with 100_100 XDX coins. + let mut sender = executor.create_raw_account_data(1_000_010, 10); + let mut secondary_signer = executor.create_xdx_raw_account_data(100_100, 100); + sender.add_balance_currency(xdx_currency_code()); + secondary_signer.add_balance_currency(xus_currency_code()); + + executor.add_account_data(&sender); + executor.add_account_data(&secondary_signer); + + let xus_amount = 10; + let xdx_amount = 100; + + let txn = multi_agent_swap_txn( + sender.account(), + secondary_signer.account(), + 10, + xus_amount, + xdx_amount, + ); + // execute transaction + let output = executor.execute_transaction(txn); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + + executor.apply_write_set(output.write_set()); + + // check that numbers in stored DB are correct + let sender_xus_balance = 1_000_010 - xus_amount; + let secondary_signer_xdx_balance = 100_100 - xdx_amount; + let updated_sender = executor + .read_account_resource(sender.account()) + .expect("sender must exist"); + let updated_sender_xus_balance = executor + .read_balance_resource(sender.account(), account::xus_currency_code()) + .expect("sender xus balance must exist"); + let updated_sender_xdx_balance = executor + .read_balance_resource(sender.account(), account::xdx_currency_code()) + .expect("sender xdx balance must exist"); + let updated_secondary_signer = executor + .read_account_resource(secondary_signer.account()) + .expect("secondary signer must exist"); + let updated_secondary_signer_xus_balance = executor + .read_balance_resource(secondary_signer.account(), account::xus_currency_code()) + .expect("secondary signer xus balance must exist"); + let updated_secondary_signer_xdx_balance = executor + .read_balance_resource(secondary_signer.account(), account::xdx_currency_code()) + .expect("secondary signer xdx balance must exist"); + assert_eq!(sender_xus_balance, updated_sender_xus_balance.coin()); + assert_eq!(xdx_amount, updated_sender_xdx_balance.coin()); + assert_eq!(xus_amount, updated_secondary_signer_xus_balance.coin()); + assert_eq!( + secondary_signer_xdx_balance, + updated_secondary_signer_xdx_balance.coin() + ); + assert_eq!(11, updated_sender.sequence_number()); + assert_eq!(100, updated_secondary_signer.sequence_number()); + assert_eq!(1, updated_sender.received_events().count(),); + assert_eq!(1, updated_sender.sent_events().count()); + assert_eq!(1, updated_secondary_signer.received_events().count()); + assert_eq!(1, updated_secondary_signer.sent_events().count()); +} + +#[test] +fn multi_agent_p2p() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + // create and publish a sender with 1_000_010 XUS coins + // and a secondary signer with 10 XUS coins. + let sender = executor.create_raw_account_data(1_000_010, 10); + let secondary_signer = executor.create_raw_account_data(10, 100); + + executor.add_account_data(&sender); + executor.add_account_data(&secondary_signer); + + let amount = 10; + + let txn = multi_agent_p2p_txn(sender.account(), secondary_signer.account(), 10, amount); + + // execute transaction + let output = executor.execute_transaction(txn); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + + executor.apply_write_set(output.write_set()); + + // check that numbers in stored DB are correct + let sender_balance = 1_000_010 - amount; + let secondary_signer_balance = 10 + amount; + let updated_sender = executor + .read_account_resource(sender.account()) + .expect("sender must exist"); + let updated_sender_balance = executor + .read_balance_resource(sender.account(), account::xus_currency_code()) + .expect("sender xus balance must exist"); + let updated_secondary_signer = executor + .read_account_resource(secondary_signer.account()) + .expect("secondary signer must exist"); + let updated_secondary_signer_balance = executor + .read_balance_resource(secondary_signer.account(), account::xus_currency_code()) + .expect("secondary signer xus balance must exist"); + + assert_eq!(sender_balance, updated_sender_balance.coin()); + assert_eq!( + secondary_signer_balance, + updated_secondary_signer_balance.coin() + ); + assert_eq!(11, updated_sender.sequence_number()); + assert_eq!(100, updated_secondary_signer.sequence_number()); + assert_eq!(0, updated_sender.received_events().count(),); + assert_eq!(1, updated_sender.sent_events().count()); + assert_eq!(1, updated_secondary_signer.received_events().count()); + assert_eq!(0, updated_secondary_signer.sent_events().count()); +} + +#[test] +fn multi_agent_wrong_number_of_signers() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + let sender = executor.create_raw_account_data(1_000_010, 10); + let secondary_signer = executor.create_raw_account_data(100_100, 100); + let third_signer = executor.create_raw_account_data(100_100, 100); + + executor.add_account_data(&sender); + executor.add_account_data(&secondary_signer); + executor.add_account_data(&third_signer); + + // Number of secondary signers given is 2 but the script only allows one secondary signer. + let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( + *sender.address(), + vec![*secondary_signer.address(), *third_signer.address()], + 10, + &sender.account().privkey, + sender.account().pubkey.clone(), + vec![ + &secondary_signer.account().privkey, + &third_signer.account().privkey, + ], + vec![ + secondary_signer.account().pubkey.clone(), + third_signer.account().pubkey.clone(), + ], + Some(multi_agent_swap_script(10, 0)), // swap between two accounts + ); + let output = executor.execute_transaction(signed_txn); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::MiscellaneousError) + ); +} diff --git a/vm/e2e-testsuite/src/tests/on_chain_configs.rs b/vm/e2e-testsuite/src/tests/on_chain_configs.rs new file mode 100644 index 0000000000..49c912c2c8 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/on_chain_configs.rs @@ -0,0 +1,228 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use diem_framework_releases::legacy::transaction_scripts::LegacyStdlibScript; +use diem_transaction_builder::stdlib::encode_update_dual_attestation_limit_script; +use diem_types::{ + account_config::CORE_CODE_ADDRESS, + on_chain_config::DiemVersion, + transaction::{Script, ScriptFunction, TransactionArgument, TransactionStatus}, + vm_status::{KeptVMStatus, StatusCode}, +}; +use diem_vm::DiemVM; +use move_core_types::{ + identifier::Identifier, language_storage::ModuleId, transaction_argument::convert_txn_args, +}; +use starcoin_language_e2e_tests::{ + account::{self, Account}, + assert_prologue_parity, + common_transactions::peer_to_peer_txn, + current_function_name, + executor::FakeExecutor, + test_with_different_versions, transaction_status_eq, + versioning::CURRENT_RELEASE_VERSIONS, +}; + +#[test] +fn initial_diem_version() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + let vm = DiemVM::new(executor.get_state_view()); + + assert_eq!( + vm.internals().diem_version().unwrap(), + DiemVersion { major: test_env.version_number } + ); + + let account = test_env.dr_account; + let txn = account + .transaction() + .script(Script::new( + LegacyStdlibScript::UpdateDiemVersion + .compiled_bytes() + .into_vec(), + vec![], + vec![TransactionArgument::U64(0), TransactionArgument::U64(test_env.version_number + 1)], + )) + .sequence_number(test_env.dr_sequence_number) + .sign(); + executor.new_block(); + executor.execute_and_apply(txn); + + let new_vm = DiemVM::new(executor.get_state_view()); + assert_eq!( + new_vm.internals().diem_version().unwrap(), + DiemVersion { major: test_env.version_number + 1 } + ); + } + } +} + +#[test] +fn drop_txn_after_reconfiguration() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let vm = DiemVM::new(executor.get_state_view()); + + assert_eq!( + vm.internals().diem_version().unwrap(), + DiemVersion { major: test_env.version_number } + ); + + let account = test_env.dr_account; + let txn = account + .transaction() + .script(Script::new( + LegacyStdlibScript::UpdateDiemVersion + .compiled_bytes() + .into_vec(), + vec![], + vec![TransactionArgument::U64(0), TransactionArgument::U64(test_env.version_number + 1)], + )) + .sequence_number(test_env.dr_sequence_number) + .sign(); + executor.new_block(); + + let sender = executor.create_raw_account_data(1_000_000, 10); + let receiver = executor.create_raw_account_data(100_000, 10); + let txn2 = peer_to_peer_txn(sender.account(), receiver.account(), 11, 1000); + + let mut output = executor.execute_block(vec![txn, txn2]).unwrap(); + assert_eq!(output.pop().unwrap().status(), &TransactionStatus::Retry) + } + } +} + +#[test] +fn updated_limit_allows_txn() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let blessed = test_env.tc_account; + // create and publish a sender with 5_000_000 coins and a receiver with 0 coins + let sender = executor.create_raw_account_data(5_000_000, 10); + let receiver = executor.create_raw_account_data(0, 10); + executor.add_account_data(&sender); + executor.add_account_data(&receiver); + + // Execute updated dual attestation limit + let new_micro_xdx_limit = 1_000_011; + let output = executor.execute_and_apply( + blessed + .transaction() + .script(encode_update_dual_attestation_limit_script( + 3, + new_micro_xdx_limit, + )) + .sequence_number(test_env.tc_sequence_number) + .sign(), + ); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + + // higher transaction works with higher limit + let transfer_amount = 1_000_010; + let txn = peer_to_peer_txn(sender.account(), receiver.account(), 10, transfer_amount); + let output = executor.execute_and_apply(txn); + assert!(transaction_status_eq( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + )); + let sender_balance = executor + .read_balance_resource(sender.account(), account::xus_currency_code()) + .expect("sender balance must exist"); + let receiver_balance = executor + .read_balance_resource(receiver.account(), account::xus_currency_code()) + .expect("receiver balance must exist"); + + assert_eq!(3_999_990, sender_balance.coin()); + assert_eq!(1_000_010, receiver_balance.coin()); + } + } +} + +#[test] +fn update_script_allow_list() { + // create a FakeExecutor with a genesis from file + let mut executor = FakeExecutor::allowlist_genesis(); + executor.set_golden_file(current_function_name!()); + let dr = Account::new_diem_root(); + // create and publish a sender with 5_000_000 coins and a receiver with 0 coins + let sender = executor.create_raw_account_data(5_000_000, 10); + executor.add_account_data(&sender); + + // Regular accounts cannot send arbitrary txn to the network. + let random_script = vec![]; + let txn = sender + .account() + .transaction() + .script(Script::new(random_script, vec![], vec![])) + .sequence_number(10) + .max_gas_amount(100_000) + .gas_unit_price(1) + .sign(); + + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::UNKNOWN_SCRIPT + ); + + // DIEM_ROOT can send arbitrary txn to the network. + let random_script = vec![]; + let txn = dr + .transaction() + .script(Script::new(random_script, vec![], vec![])) + .sequence_number(0) + .sign(); + + assert_eq!( + executor.execute_transaction(txn).status(), + &TransactionStatus::Keep(KeptVMStatus::MiscellaneousError) + ); +} + +#[test] +fn update_consensus_config() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + let account = test_env.dr_account; + let generate_txn = |seq_num, fun_name, config| { + // sliding nonce + let mut args = vec![TransactionArgument::U64(seq_num)]; + if let Some(config) = config { + args.push(TransactionArgument::U8Vector(config)); + } + account + .transaction() + .script_function(ScriptFunction::new( + ModuleId::new( + CORE_CODE_ADDRESS, + Identifier::new("SystemAdministrationScripts").unwrap(), + ), + Identifier::new(fun_name).unwrap(), + vec![], + convert_txn_args(&args), + )) + .sequence_number(seq_num) + .sign() + }; + let seq_num = test_env.dr_sequence_number; + + if test_env.version_number == 1 { + assert_eq!(executor.execute_transaction(generate_txn(seq_num, "update_dime_consensus_config", Some(vec![1,2,3]))).status(), &TransactionStatus::Discard(StatusCode::FEATURE_UNDER_GATING)); + } + + if test_env.version_number == 2 { + // update abort when uninitialized + assert!(matches!(executor.execute_transaction(generate_txn(seq_num, "update_diem_consensus_config", Some(vec![1,2,3]))).status(), &TransactionStatus::Keep(KeptVMStatus::MoveAbort(_, _)))); + assert_eq!(executor.execute_and_apply(generate_txn(seq_num, "initialize_diem_consensus_config", None)).status(), &TransactionStatus::Keep(KeptVMStatus::Executed)); + assert_eq!(executor.execute_and_apply(generate_txn(seq_num + 1, "update_diem_consensus_config", Some(vec![1,2,3]))).status(), &TransactionStatus::Keep(KeptVMStatus::Executed)); + } + + } + } +} diff --git a/vm/e2e-testsuite/src/tests/parallel_execution.rs b/vm/e2e-testsuite/src/tests/parallel_execution.rs new file mode 100644 index 0000000000..aee05760d8 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/parallel_execution.rs @@ -0,0 +1,242 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use crate::tests::peer_to_peer::{check_and_apply_transfer_output, create_cyclic_transfers}; +use starcoin_crypto::{ed25519::Ed25519PrivateKey, HashValue, PrivateKey, Uniform}; +use diem_types::{ + block_metadata::BlockMetadata, + on_chain_config::{OnChainConfig, ParallelExecutionConfig, ValidatorSet}, + transaction::{ + authenticator::AuthenticationKey, Script, Transaction, TransactionArgument, + TransactionStatus, WriteSetPayload, + }, + vm_status::{KeptVMStatus, StatusCode}, +}; +use starcoin_vm::parallel_executor::ParallelDiemVM; +use move_ir_compiler::Compiler; +use starcoin_language_e2e_tests::{ + account, common_transactions::rotate_key_txn, executor::FakeExecutor, +}; + +#[test] +fn peer_to_peer_with_prologue_parallel() { + let mut executor = FakeExecutor::from_fresh_genesis(); + let account_size = 1000usize; + let initial_balance = 2_000_000u64; + let initial_seq_num = 10u64; + let accounts = executor.create_accounts(account_size, initial_balance, initial_seq_num); + + // set up the transactions + let transfer_amount = 1_000; + + // insert a block prologue transaction + let (txns_info, transfer_txns) = create_cyclic_transfers(&executor, &accounts, transfer_amount); + + let mut txns = transfer_txns + .into_iter() + .map(Transaction::UserTransaction) + .collect::>(); + let validator_set = ValidatorSet::fetch_config(executor.get_state_view()) + .expect("Unable to retrieve the validator set from storage"); + let new_block = BlockMetadata::new( + HashValue::zero(), + 0, + 1, + vec![], + *validator_set.payload()[0].account_address(), + ); + + txns.insert(0, Transaction::BlockMetadata(new_block)); + + let (mut results, parallel_status) = + ParallelDiemVM::execute_block(txns, executor.get_state_view()).unwrap(); + + assert!(parallel_status.is_none()); + + results.remove(0); + + check_and_apply_transfer_output(&mut executor, &txns_info, &results) +} + +#[test] +fn rotate_ed25519_key() { + let balance = 1_000_000; + let mut executor = FakeExecutor::from_fresh_genesis(); + + // create and publish sender + let mut sender = executor.create_raw_account_data(balance, 10); + executor.add_account_data(&sender); + + let privkey = Ed25519PrivateKey::generate_for_testing(); + let pubkey = privkey.public_key(); + let new_key_hash = AuthenticationKey::ed25519(&pubkey).to_vec(); + let txn = rotate_key_txn(sender.account(), new_key_hash.clone(), 10); + + // execute transaction + let (mut results, parallel_status) = ParallelDiemVM::execute_block( + vec![Transaction::UserTransaction(txn)], + executor.get_state_view(), + ) + .unwrap(); + + assert!(parallel_status.is_none()); + + let output = results.pop().unwrap(); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed), + ); + executor.apply_write_set(output.write_set()); + + // Check that numbers in store are correct. + let updated_sender = executor + .read_account_resource(sender.account()) + .expect("sender must exist"); + let updated_sender_balance = executor + .read_balance_resource(sender.account(), account::xus_currency_code()) + .expect("sender balance must exist"); + assert_eq!(new_key_hash, updated_sender.authentication_key().to_vec()); + assert_eq!(balance, updated_sender_balance.coin()); + assert_eq!(11, updated_sender.sequence_number()); + + // Check that transactions cannot be sent with the old key any more. + let old_key_txn = rotate_key_txn(sender.account(), vec![], 11); + let old_key_output = &executor.execute_transaction(old_key_txn); + assert_eq!( + old_key_output.status(), + &TransactionStatus::Discard(StatusCode::INVALID_AUTH_KEY), + ); + + // Check that transactions can be sent with the new key. + sender.rotate_key(privkey, pubkey); + let new_key_txn = rotate_key_txn(sender.account(), new_key_hash, 11); + let new_key_output = &executor.execute_transaction(new_key_txn); + assert_eq!( + new_key_output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed), + ); +} + +#[test] +fn parallel_execution_config() { + let mut executor = FakeExecutor::from_fresh_genesis(); + let account_size = 1000usize; + let initial_balance = 2_000_000u64; + let initial_seq_num = 10u64; + let accounts = executor.create_accounts(account_size, initial_balance, initial_seq_num); + + // set up the transactions + let transfer_amount = 1_000; + + // insert a block prologue transaction + let (txns_info, transfer_txns) = create_cyclic_transfers(&executor, &accounts, transfer_amount); + + executor.enable_parallel_execution(); + + let outputs = executor.execute_block(transfer_txns).unwrap(); + + check_and_apply_transfer_output(&mut executor, &txns_info, &outputs); + + executor.disable_parallel_execution(); + + assert_eq!( + ParallelExecutionConfig::fetch_config(executor.get_state_view()), + Some(ParallelExecutionConfig { + read_write_analysis_result: None, + }) + ); +} + +#[test] +fn parallel_execution_genesis() { + let mut executor = FakeExecutor::parallel_genesis(); + let account_size = 1000usize; + let initial_balance = 2_000_000u64; + let initial_seq_num = 10u64; + let accounts = executor.create_accounts(account_size, initial_balance, initial_seq_num); + + // set up the transactions + let transfer_amount = 1_000; + + assert!( + ParallelExecutionConfig::fetch_config(executor.get_state_view()) + .unwrap() + .read_write_analysis_result + .is_some() + ); + + // insert a block prologue transaction + let (txns_info, transfer_txns) = create_cyclic_transfers(&executor, &accounts, transfer_amount); + let outputs = executor.execute_block(transfer_txns).unwrap(); + + check_and_apply_transfer_output(&mut executor, &txns_info, &outputs); + + executor.disable_parallel_execution(); + + assert_eq!( + ParallelExecutionConfig::fetch_config(executor.get_state_view()), + Some(ParallelExecutionConfig { + read_write_analysis_result: None, + }) + ); +} + +#[test] +fn parallel_execution_with_bad_config() { + let mut executor = FakeExecutor::from_fresh_genesis(); + let account_size = 1000usize; + let initial_balance = 2_000_000u64; + let initial_seq_num = 10u64; + let accounts = executor.create_accounts(account_size, initial_balance, initial_seq_num); + + // set up the transactions + let transfer_amount = 1_000; + + // insert a block prologue transaction + let (txns_info, transfer_txns) = create_cyclic_transfers(&executor, &accounts, transfer_amount); + + let diem_root = account::Account::new_diem_root(); + let seq_num = executor + .read_account_resource_at_address(diem_root.address()) + .unwrap() + .sequence_number(); + + // Enable parallel execution with a malformed config + + let script_body = { + let code = r#" +import 0x1.ParallelExecutionConfig; + +main(dr_account: signer, account: signer, payload: vector) { +label b0: + ParallelExecutionConfig.enable_parallel_execution_with_config(&dr_account, move(payload)); + return; +} +"#; + + let compiler = Compiler { + deps: diem_framework_releases::current_modules().iter().collect(), + }; + compiler.into_script_blob(code).expect("Failed to compile") + }; + + let txn = diem_root + .transaction() + .write_set(WriteSetPayload::Script { + script: Script::new( + script_body, + vec![], + vec![TransactionArgument::U8Vector(vec![])], + ), + execute_as: *diem_root.address(), + }) + .sequence_number(seq_num) + .sign(); + executor.execute_and_apply(txn); + + // Make sure transactions can still be processed correctly in sequential mode. + + let outputs = executor.execute_block(transfer_txns).unwrap(); + + check_and_apply_transfer_output(&mut executor, &txns_info, &outputs); +} diff --git a/vm/e2e-testsuite/src/tests/peer_to_peer.rs b/vm/e2e-testsuite/src/tests/peer_to_peer.rs new file mode 100644 index 0000000000..25225cad6b --- /dev/null +++ b/vm/e2e-testsuite/src/tests/peer_to_peer.rs @@ -0,0 +1,595 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use diem_types::{ + account_config::{ReceivedPaymentEvent, SentPaymentEvent}, + transaction::{SignedTransaction, TransactionOutput, TransactionStatus}, + vm_status::{known_locations, KeptVMStatus}, +}; +use starcoin_language_e2e_tests::{ + account::{self, Account}, + common_transactions::peer_to_peer_txn, + executor::FakeExecutor, + test_with_different_versions, transaction_status_eq, + versioning::CURRENT_RELEASE_VERSIONS, +}; +use std::{convert::TryFrom, time::Instant}; + +#[test] +fn single_peer_to_peer_with_event() { + ::starcoin_logger::Logger::init_for_testing(); + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + // create and publish a sender with 1_000_000 coins and a receiver with 100_000 coins + let sender = executor.create_raw_account_data(1_000_000, 10); + let receiver = executor.create_raw_account_data(100_000, 10); + executor.add_account_data(&sender); + executor.add_account_data(&receiver); + + let transfer_amount = 1_000; + let txn = peer_to_peer_txn(sender.account(), receiver.account(), 10, transfer_amount); + + // execute transaction + let output = executor.execute_transaction(txn); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + + executor.apply_write_set(output.write_set()); + + // check that numbers in stored DB are correct + let sender_balance = 1_000_000 - transfer_amount; + let receiver_balance = 100_000 + transfer_amount; + let updated_sender = executor + .read_account_resource(sender.account()) + .expect("sender must exist"); + let updated_sender_balance = executor + .read_balance_resource(sender.account(), account::xus_currency_code()) + .expect("sender balance must exist"); + let updated_receiver = executor + .read_account_resource(receiver.account()) + .expect("receiver must exist"); + let updated_receiver_balance = executor + .read_balance_resource(receiver.account(), account::xus_currency_code()) + .expect("receiver balance must exist"); + assert_eq!(receiver_balance, updated_receiver_balance.coin()); + assert_eq!(sender_balance, updated_sender_balance.coin()); + assert_eq!(11, updated_sender.sequence_number()); + assert_eq!(0, updated_sender.received_events().count(),); + assert_eq!(1, updated_sender.sent_events().count()); + assert_eq!(1, updated_receiver.received_events().count()); + assert_eq!(0, updated_receiver.sent_events().count()); + + let rec_ev_path = receiver.received_events_key().to_vec(); + let sent_ev_path = sender.sent_events_key().to_vec(); + for event in output.events() { + assert!( + rec_ev_path.as_slice() == event.key().as_bytes() + || sent_ev_path.as_slice() == event.key().as_bytes() + ); + } + } + } +} + +// TODO test no longer simple as the legacy version takes an &signer but all +// new scripts take an owned signer +// #[test] +// fn single_peer_to_peer_with_padding() { +// ::diem_logger::Logger::init_for_testing(); +// // create a FakeExecutor with a genesis from file +// let mut executor = +// FakeExecutor::from_genesis_with_options(VMPublishingOption::custom_scripts()); +// executor.set_golden_file(current_function_name!()); + +// // create and publish a sender with 1_000_000 coins and a receiver with 100_000 coins +// let sender = executor.create_raw_account_data(1_000_000, 10); +// let receiver = executor.create_raw_account_data(100_000, 10); +// executor.add_account_data(&sender); +// executor.add_account_data(&receiver); + +// let transfer_amount = 1_000; +// let padded_script = { +// let mut script_mut = CompiledScript::deserialize( +// &LegacyStdlibScript::PeerToPeerWithMetadata +// .compiled_bytes() +// .into_vec(), +// ) +// .unwrap() +// .into_inner(); +// script_mut +// .code +// .code +// .extend(std::iter::repeat(Bytecode::Ret).take(1000)); +// let mut script_bytes = vec![]; +// script_mut +// .freeze() +// .unwrap() +// .serialize(&mut script_bytes) +// .unwrap(); + +// Script::new( +// script_bytes, +// vec![account_config::xus_tag()], +// vec![ +// TransactionArgument::Address(*receiver.address()), +// TransactionArgument::U64(transfer_amount), +// TransactionArgument::U8Vector(vec![]), +// TransactionArgument::U8Vector(vec![]), +// ], +// ) +// }; + +// let txn = sender +// .account() +// .transaction() +// .script(padded_script) +// .sequence_number(10) +// .sign(); +// let unpadded_txn = peer_to_peer_txn(sender.account(), receiver.account(), 10, transfer_amount); +// assert!(txn.raw_txn_bytes_len() > unpadded_txn.raw_txn_bytes_len()); +// // execute transaction +// let output = executor.execute_transaction(txn); +// assert_eq!( +// output.status(), +// &TransactionStatus::Keep(KeptVMStatus::Executed) +// ); + +// executor.apply_write_set(output.write_set()); + +// // check that numbers in stored DB are correct +// let sender_balance = 1_000_000 - transfer_amount; +// let receiver_balance = 100_000 + transfer_amount; +// let updated_sender = executor +// .read_account_resource(sender.account()) +// .expect("sender must exist"); +// let updated_sender_balance = executor +// .read_balance_resource(sender.account(), account::xus_currency_code()) +// .expect("sender balance must exist"); +// let updated_receiver_balance = executor +// .read_balance_resource(receiver.account(), account::xus_currency_code()) +// .expect("receiver balance must exist"); +// assert_eq!(receiver_balance, updated_receiver_balance.coin()); +// assert_eq!(sender_balance, updated_sender_balance.coin()); +// assert_eq!(11, updated_sender.sequence_number()); +// } + +#[test] +fn few_peer_to_peer_with_event() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + // create and publish a sender with 3_000_000 coins and a receiver with 3_000_000 coins + let sender = executor.create_raw_account_data(3_000_000, 10); + let receiver = executor.create_raw_account_data(3_000_000, 10); + executor.add_account_data(&sender); + executor.add_account_data(&receiver); + + let transfer_amount = 1_000; + + // execute transaction + let txns: Vec = vec![ + peer_to_peer_txn(sender.account(), receiver.account(), 10, transfer_amount), + peer_to_peer_txn(sender.account(), receiver.account(), 11, transfer_amount), + peer_to_peer_txn(sender.account(), receiver.account(), 12, transfer_amount), + peer_to_peer_txn(sender.account(), receiver.account(), 13, transfer_amount), + ]; + let output = executor.execute_block(txns).unwrap(); + for (idx, txn_output) in output.iter().enumerate() { + assert_eq!( + txn_output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + + // check events + for event in txn_output.events() { + if let Ok(payload) = SentPaymentEvent::try_from(event) { + assert_eq!(transfer_amount, payload.amount()); + assert_eq!(receiver.address(), &payload.receiver()); + } else if let Ok(payload) = ReceivedPaymentEvent::try_from(event) { + assert_eq!(transfer_amount, payload.amount()); + assert_eq!(sender.address(), &payload.sender()); + } else { + panic!("Unexpected Event Type") + } + } + + let original_sender_balance = executor + .read_balance_resource(sender.account(), account::xus_currency_code()) + .expect("sender balance must exist"); + let original_receiver_balance = executor + .read_balance_resource(receiver.account(), account::xus_currency_code()) + .expect("receiver balcne must exist"); + executor.apply_write_set(txn_output.write_set()); + + // check that numbers in stored DB are correct + let sender_balance = original_sender_balance.coin() - transfer_amount; + let receiver_balance = original_receiver_balance.coin() + transfer_amount; + let updated_sender = executor + .read_account_resource(sender.account()) + .expect("sender must exist"); + let updated_sender_balance = executor + .read_balance_resource(sender.account(), account::xus_currency_code()) + .expect("sender balance must exist"); + let updated_receiver = executor + .read_account_resource(receiver.account()) + .expect("receiver must exist"); + let updated_receiver_balance = executor + .read_balance_resource(receiver.account(), account::xus_currency_code()) + .expect("receiver balance must exist"); + assert_eq!(receiver_balance, updated_receiver_balance.coin()); + assert_eq!(sender_balance, updated_sender_balance.coin()); + assert_eq!(11 + idx as u64, updated_sender.sequence_number()); + assert_eq!(0, updated_sender.received_events().count()); + assert_eq!(idx as u64 + 1, updated_sender.sent_events().count()); + assert_eq!(idx as u64 + 1, updated_receiver.received_events().count()); + assert_eq!(0, updated_receiver.sent_events().count()); + } + } + } +} + +/// Test that a zero-amount transaction fails, per policy. +#[test] +fn zero_amount_peer_to_peer() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let sequence_number = 10; + let sender = executor.create_raw_account_data(1_000_000, sequence_number); + let receiver = executor.create_raw_account_data(100_000, sequence_number); + executor.add_account_data(&sender); + executor.add_account_data(&receiver); + + let transfer_amount = 0; + let txn = peer_to_peer_txn( + sender.account(), + receiver.account(), + sequence_number, + transfer_amount, + ); + + let output = &executor.execute_transaction(txn); + // Error code 7 means that the transaction was a zero-amount one. + assert!(transaction_status_eq( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::MoveAbort( + known_locations::diem_account_module_abort(), + 519 + )), + )); + } + } +} + +// Holder for transaction data; arguments to transactions. +pub(crate) struct TxnInfo { + pub sender: Account, + pub receiver: Account, + pub transfer_amount: u64, +} + +impl TxnInfo { + fn new(sender: &Account, receiver: &Account, transfer_amount: u64) -> Self { + TxnInfo { + sender: sender.clone(), + receiver: receiver.clone(), + transfer_amount, + } + } +} + +// Create a cyclic transfer around a slice of Accounts. +// Each Account makes a transfer for the same amount to the next DiemAccount. +pub(crate) fn create_cyclic_transfers( + executor: &FakeExecutor, + accounts: &[Account], + transfer_amount: u64, +) -> (Vec, Vec) { + let mut txns: Vec = Vec::new(); + let mut txns_info: Vec = Vec::new(); + // loop through all transactions and let each transfer the same amount to the next one + let count = accounts.len(); + for i in 0..count { + let sender = &accounts[i]; + let sender_resource = executor + .read_account_resource(sender) + .expect("sender must exist"); + let seq_num = sender_resource.sequence_number(); + let receiver = &accounts[(i + 1) % count]; + + let txn = peer_to_peer_txn(sender, receiver, seq_num, transfer_amount); + txns.push(txn); + txns_info.push(TxnInfo::new(sender, receiver, transfer_amount)); + } + (txns_info, txns) +} + +// Create a one to many transfer around a slice of Accounts. +// The first account is the payer and all others are receivers. +fn create_one_to_many_transfers( + executor: &FakeExecutor, + accounts: &[Account], + transfer_amount: u64, +) -> (Vec, Vec) { + let mut txns: Vec = Vec::new(); + let mut txns_info: Vec = Vec::new(); + // grab account 0 as a sender + let sender = &accounts[0]; + let sender_resource = executor + .read_account_resource(sender) + .expect("sender must exist"); + let seq_num = sender_resource.sequence_number(); + // loop through all transactions and let each transfer the same amount to the next one + let count = accounts.len(); + for (i, receiver) in accounts.iter().enumerate().take(count).skip(1) { + // let receiver = &accounts[i]; + + let txn = peer_to_peer_txn(sender, receiver, seq_num + i as u64 - 1, transfer_amount); + txns.push(txn); + txns_info.push(TxnInfo::new(sender, receiver, transfer_amount)); + } + (txns_info, txns) +} + +// Create a many to one transfer around a slice of Accounts. +// The first account is the receiver and all others are payers. +fn create_many_to_one_transfers( + executor: &FakeExecutor, + accounts: &[Account], + transfer_amount: u64, +) -> (Vec, Vec) { + let mut txns: Vec = Vec::new(); + let mut txns_info: Vec = Vec::new(); + // grab account 0 as a sender + let receiver = &accounts[0]; + // loop through all transactions and let each transfer the same amount to the next one + let count = accounts.len(); + for sender in accounts.iter().take(count).skip(1) { + //let sender = &accounts[i]; + let sender_resource = executor + .read_account_resource(sender) + .expect("sender must exist"); + let seq_num = sender_resource.sequence_number(); + + let txn = peer_to_peer_txn(sender, receiver, seq_num, transfer_amount); + txns.push(txn); + txns_info.push(TxnInfo::new(sender, receiver, transfer_amount)); + } + (txns_info, txns) +} + +// Verify a transfer output. +// Checks that sender and receiver in a peer to peer transaction are in proper +// state after a successful transfer. +// The transaction arguments are provided in txn_args. +// Apply the WriteSet to the data store. +pub(crate) fn check_and_apply_transfer_output( + executor: &mut FakeExecutor, + txn_args: &[TxnInfo], + output: &[TransactionOutput], +) { + let count = output.len(); + for i in 0..count { + let txn_info = &txn_args[i]; + let sender = &txn_info.sender; + let receiver = &txn_info.receiver; + let transfer_amount = txn_info.transfer_amount; + let sender_resource = executor + .read_account_resource(sender) + .expect("sender must exist"); + let sender_balance = executor + .read_balance_resource(sender, account::xus_currency_code()) + .expect("sender balance must exist"); + let sender_initial_balance = sender_balance.coin(); + let sender_seq_num = sender_resource.sequence_number(); + let receiver_initial_balance = executor + .read_balance_resource(receiver, account::xus_currency_code()) + .expect("receiver balance must exist") + .coin(); + + // apply single transaction to DB + let txn_output = &output[i]; + executor.apply_write_set(txn_output.write_set()); + + // check that numbers stored in DB are correct + let sender_balance = sender_initial_balance - transfer_amount; + let receiver_balance = receiver_initial_balance + transfer_amount; + let updated_sender = executor + .read_account_resource(sender) + .expect("sender must exist"); + let updated_sender_balance = executor + .read_balance_resource(sender, account::xus_currency_code()) + .expect("sender balance must exist"); + let updated_receiver_balance = executor + .read_balance_resource(receiver, account::xus_currency_code()) + .expect("receiver balance must exist"); + assert_eq!(receiver_balance, updated_receiver_balance.coin()); + assert_eq!(sender_balance, updated_sender_balance.coin()); + assert_eq!(sender_seq_num + 1, updated_sender.sequence_number()); + } +} + +// simple utility to print all account to visually inspect account data +fn print_accounts(executor: &FakeExecutor, accounts: &[Account]) { + for account in accounts { + let account_resource = executor + .read_account_resource(account) + .expect("sender must exist"); + println!("{:?}", account_resource); + } +} + +#[test] +fn cycle_peer_to_peer() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let account_size = 100usize; + let initial_balance = 2_000_000u64; + let initial_seq_num = 10u64; + let accounts = executor.create_accounts(account_size, initial_balance, initial_seq_num); + + // set up the transactions + let transfer_amount = 1_000; + let (txns_info, txns) = create_cyclic_transfers(&executor, &accounts, transfer_amount); + + // execute transaction + let mut execution_time = 0u128; + let now = Instant::now(); + let output = executor.execute_block(txns).unwrap(); + execution_time += now.elapsed().as_nanos(); + println!("EXECUTION TIME: {}", execution_time); + for txn_output in &output { + assert_eq!( + txn_output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + } + assert_eq!(accounts.len(), output.len()); + + check_and_apply_transfer_output(&mut executor, &txns_info, &output); + print_accounts(&executor, &accounts); + } + } +} + +#[test] +fn cycle_peer_to_peer_multi_block() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let account_size = 100usize; + let initial_balance = 1_000_000u64; + let initial_seq_num = 10u64; + let accounts = executor.create_accounts(account_size, initial_balance, initial_seq_num); + + // set up the transactions + let transfer_amount = 1_000; + let block_count = 5u64; + let cycle = account_size / (block_count as usize); + let mut range_left = 0usize; + let mut execution_time = 0u128; + for _i in 0..block_count { + range_left = if range_left + cycle >= account_size { + account_size - cycle + } else { + range_left + }; + let (txns_info, txns) = create_cyclic_transfers( + &executor, + &accounts[range_left..range_left + cycle], + transfer_amount, + ); + + // execute transaction + let now = Instant::now(); + let output = executor.execute_block(txns).unwrap(); + execution_time += now.elapsed().as_nanos(); + for txn_output in &output { + assert_eq!( + txn_output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + } + assert_eq!(cycle, output.len()); + check_and_apply_transfer_output(&mut executor, &txns_info, &output); + range_left = (range_left + cycle) % account_size; + } + println!("EXECUTION TIME: {}", execution_time); + print_accounts(&executor, &accounts); + } + } +} + +#[test] +fn one_to_many_peer_to_peer() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let account_size = 100usize; + let initial_balance = 100_000_000u64; + let initial_seq_num = 10u64; + let accounts = executor.create_accounts(account_size, initial_balance, initial_seq_num); + + // set up the transactions + let transfer_amount = 1_000; + let block_count = 2u64; + let cycle = account_size / (block_count as usize); + let mut range_left = 0usize; + let mut execution_time = 0u128; + for _i in 0..block_count { + range_left = if range_left + cycle >= account_size { + account_size - cycle + } else { + range_left + }; + let (txns_info, txns) = create_one_to_many_transfers( + &executor, + &accounts[range_left..range_left + cycle], + transfer_amount, + ); + + // execute transaction + let now = Instant::now(); + let output = executor.execute_block(txns).unwrap(); + execution_time += now.elapsed().as_nanos(); + for txn_output in &output { + assert_eq!( + txn_output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + } + assert_eq!(cycle - 1, output.len()); + check_and_apply_transfer_output(&mut executor, &txns_info, &output); + range_left = (range_left + cycle) % account_size; + } + println!("EXECUTION TIME: {}", execution_time); + print_accounts(&executor, &accounts); + } + } +} + +#[test] +fn many_to_one_peer_to_peer() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let account_size = 100usize; + let initial_balance = 1_000_000u64; + let initial_seq_num = 10u64; + let accounts = executor.create_accounts(account_size, initial_balance, initial_seq_num); + + // set up the transactions + let transfer_amount = 1_000; + let block_count = 2u64; + let cycle = account_size / (block_count as usize); + let mut range_left = 0usize; + let mut execution_time = 0u128; + for _i in 0..block_count { + range_left = if range_left + cycle >= account_size { + account_size - cycle + } else { + range_left + }; + let (txns_info, txns) = create_many_to_one_transfers( + &executor, + &accounts[range_left..range_left + cycle], + transfer_amount, + ); + + // execute transaction + let now = Instant::now(); + let output = executor.execute_block(txns).unwrap(); + execution_time += now.elapsed().as_nanos(); + for txn_output in &output { + assert_eq!( + txn_output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + } + assert_eq!(cycle - 1, output.len()); + check_and_apply_transfer_output(&mut executor, &txns_info, &output); + range_left = (range_left + cycle) % account_size; + } + println!("EXECUTION TIME: {}", execution_time); + print_accounts(&executor, &accounts); + } + } +} diff --git a/vm/e2e-testsuite/src/tests/preburn_queue.rs b/vm/e2e-testsuite/src/tests/preburn_queue.rs new file mode 100644 index 0000000000..882891356a --- /dev/null +++ b/vm/e2e-testsuite/src/tests/preburn_queue.rs @@ -0,0 +1,340 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use diem_transaction_builder::stdlib::*; +use diem_types::{account_config, transaction::TransactionOutput}; +use move_core_types::vm_status::{DiscardedVMStatus, KeptVMStatus}; +use starcoin_language_e2e_tests::{ + account::Account, current_function_name, executor::FakeExecutor, utils, +}; + +fn create_preburn_balance( + executor: &mut FakeExecutor, + dd_account: &Account, + preburn_amount: u64, + dd_seqno: &mut u64, + should_fail: bool, +) -> Option { + let script = encode_preburn_script(account_config::xus_tag(), preburn_amount); + let txn = dd_account + .transaction() + .script(script) + .sequence_number(*dd_seqno) + .sign(); + if should_fail { + Some(executor.execute_transaction(txn)) + } else { + executor.execute_and_apply(txn); + *dd_seqno = dd_seqno.checked_add(1).unwrap(); + None + } +} + +fn burn_old( + executor: &mut FakeExecutor, + tc_account: &Account, + tc_seqno: &mut u64, + should_fail: bool, +) -> Option { + let txn = tc_account + .transaction() + .script(encode_burn_script( + account_config::xus_tag(), + 0, + account_config::testnet_dd_account_address(), + )) + .sequence_number(*tc_seqno) + .sign(); + if should_fail { + Some(executor.execute_transaction(txn)) + } else { + executor.execute_and_apply(txn); + *tc_seqno = tc_seqno.checked_add(1).unwrap(); + None + } +} + +fn cancel_burn_old( + executor: &mut FakeExecutor, + tc_account: &Account, + tc_seqno: &mut u64, + should_fail: bool, +) -> Option { + let txn = tc_account + .transaction() + .script(encode_cancel_burn_script( + account_config::xus_tag(), + account_config::testnet_dd_account_address(), + )) + .sequence_number(*tc_seqno) + .sign(); + if should_fail { + Some(executor.execute_transaction(txn)) + } else { + executor.execute_and_apply(txn); + *tc_seqno = tc_seqno.checked_add(1).unwrap(); + None + } +} + +fn burn_with_amount_new( + executor: &mut FakeExecutor, + amount: u64, + tc_account: &Account, + tc_seqno: &mut u64, + should_fail: bool, +) -> Option { + let txn = tc_account + .transaction() + .payload(encode_burn_with_amount_script_function( + account_config::xus_tag(), + 0, + account_config::testnet_dd_account_address(), + amount, + )) + .sequence_number(*tc_seqno) + .sign(); + if should_fail { + Some(executor.execute_transaction(txn)) + } else { + executor.execute_and_apply(txn); + *tc_seqno = tc_seqno.checked_add(1).unwrap(); + None + } +} + +fn cancel_burn_with_amount_new( + executor: &mut FakeExecutor, + amount: u64, + tc_account: &Account, + tc_seqno: &mut u64, + should_fail: bool, +) -> Option { + let txn = tc_account + .transaction() + .payload(encode_cancel_burn_with_amount_script_function( + account_config::xus_tag(), + account_config::testnet_dd_account_address(), + amount, + )) + .sequence_number(*tc_seqno) + .sign(); + if should_fail { + Some(executor.execute_transaction(txn)) + } else { + executor.execute_and_apply(txn); + *tc_seqno = tc_seqno.checked_add(1).unwrap(); + None + } +} + +/// Make sure we can preburn and before the upgrade with the old scripts, and that we can +/// preburn and burn after the upgrade with the new scripts (and the old preburn script). Note +/// that the preburn balance at the time of upgrade is zero. +#[test] +fn concurrent_preburns_test_upgrade_empty_preburn() { + let (mut executor, dr_account, tc_account, dd_account) = utils::start_with_released_df(); + let mut tc_seqno = 0; + let mut dd_seqno = 0; + let mut dr_seqno = 1; + executor.set_golden_file(current_function_name!()); + + create_preburn_balance(&mut executor, &dd_account, 10, &mut dd_seqno, false); + burn_old(&mut executor, &tc_account, &mut tc_seqno, false); + + create_preburn_balance(&mut executor, &dd_account, 10, &mut dd_seqno, false); + cancel_burn_old(&mut executor, &tc_account, &mut tc_seqno, false); + + // Upgrade the DF + utils::upgrade_df(&mut executor, &dr_account, &mut dr_seqno, Some(2)); + + // Now make sure that we can upgrade the DD + create_preburn_balance(&mut executor, &dd_account, 100, &mut dd_seqno, false); + burn_with_amount_new(&mut executor, 100, &tc_account, &mut tc_seqno, false); + + // Make sure now that we're upgraded that we can keep doing this + create_preburn_balance(&mut executor, &dd_account, 10, &mut dd_seqno, false); + cancel_burn_with_amount_new(&mut executor, 10, &tc_account, &mut tc_seqno, false); +} + +/// Make sure we can preburn and before the upgrade with the old scripts, and that we can +/// preburn and burn after the upgrade with the new scripts (and the old preburn script) and that +/// concurrent preburns are supported immediately without any additional input from TC. Note that +/// the preburn balance at the time of upgrade is zero. +#[test] +fn concurrent_preburns_test_upgrade_empty_preburn_multiple_initial_preburns() { + let (mut executor, dr_account, tc_account, dd_account) = utils::start_with_released_df(); + let mut tc_seqno = 0; + let mut dd_seqno = 0; + let mut dr_seqno = 1; + executor.set_golden_file(current_function_name!()); + + create_preburn_balance(&mut executor, &dd_account, 10, &mut dd_seqno, false); + burn_old(&mut executor, &tc_account, &mut tc_seqno, false); + + create_preburn_balance(&mut executor, &dd_account, 10, &mut dd_seqno, false); + cancel_burn_old(&mut executor, &tc_account, &mut tc_seqno, false); + + // Upgrade the DF + utils::upgrade_df(&mut executor, &dr_account, &mut dr_seqno, Some(2)); + + // Now make sure that we can upgrade the DD + create_preburn_balance(&mut executor, &dd_account, 100, &mut dd_seqno, false); + // Make sure we can now have multiple preburn requests + create_preburn_balance(&mut executor, &dd_account, 20, &mut dd_seqno, false); + + // burn and cancel in a different order + burn_with_amount_new(&mut executor, 20, &tc_account, &mut tc_seqno, false); + cancel_burn_with_amount_new(&mut executor, 100, &tc_account, &mut tc_seqno, false); +} + +/// If the DF is upgraded and a DD has a non-zero preburn balance at the time of the +/// upgrade, make sure that the system doesn't reach a stuck state. But, the DD will need to +/// upgrade with a nonzero preburn first. +#[test] +fn concurrent_preburns_test_upgrade_existing_balance_at_upgrade() { + let (mut executor, dr_account, tc_account, dd_account) = utils::start_with_released_df(); + let mut tc_seqno = 0; + let mut dd_seqno = 0; + let mut dr_seqno = 1; + executor.set_golden_file(current_function_name!()); + + create_preburn_balance(&mut executor, &dd_account, 10, &mut dd_seqno, false); + + // Upgrade the DF + utils::upgrade_df(&mut executor, &dr_account, &mut dr_seqno, Some(2)); + + // The new burn/cancel burn scripts will fail since the preburn hasn't been upgraded yet + assert!(matches!( + cancel_burn_with_amount_new(&mut executor, 100, &tc_account, &mut tc_seqno, true) + .unwrap() + .status() + .status() + .unwrap(), + KeptVMStatus::MoveAbort(_, 2821) + )); + assert!(matches!( + burn_with_amount_new(&mut executor, 100, &tc_account, &mut tc_seqno, true) + .unwrap() + .status() + .status() + .unwrap(), + KeptVMStatus::MoveAbort(_, 2821) + )); + + // Now upgrade the preburn (recall it already has a nonzero balance). + create_preburn_balance(&mut executor, &dd_account, 100, &mut dd_seqno, false); + // Now the new burn/cancel burn scripts will succeed. + cancel_burn_with_amount_new(&mut executor, 100, &tc_account, &mut tc_seqno, false); + burn_with_amount_new(&mut executor, 10, &tc_account, &mut tc_seqno, false); +} + +/// Make sure we can preburn before the upgrade with the old scripts. +/// Test that the old `burn` and `cancel_burn` scripts will fail after the upgrade though, even if +/// the old data hasn't been upgraded yet. +#[test] +fn concurrent_preburns_test_upgrade_old_data_new_df_old_scripts_fail() { + let (mut executor, dr_account, tc_account, dd_account) = utils::start_with_released_df(); + let mut tc_seqno = 0; + let mut dd_seqno = 0; + let mut dr_seqno = 1; + executor.set_golden_file(current_function_name!()); + + create_preburn_balance(&mut executor, &dd_account, 10, &mut dd_seqno, false); + burn_old(&mut executor, &tc_account, &mut tc_seqno, false); + + create_preburn_balance(&mut executor, &dd_account, 10, &mut dd_seqno, false); + cancel_burn_old(&mut executor, &tc_account, &mut tc_seqno, false); + + // Upgrade the DF + utils::upgrade_df(&mut executor, &dr_account, &mut dr_seqno, Some(2)); + + // the old scripts will now fail with a `MISCELLANEOUS_ERROR` + assert_eq!( + burn_old(&mut executor, &tc_account, &mut tc_seqno, true) + .unwrap() + .status() + .status() + .unwrap(), + KeptVMStatus::MiscellaneousError + ); + + assert_eq!( + cancel_burn_old(&mut executor, &tc_account, &mut tc_seqno, true) + .unwrap() + .status() + .status() + .unwrap(), + KeptVMStatus::MiscellaneousError + ); +} + +/// Make sure we can preburn before the upgrade with the old scripts, and that we can +/// preburn and burn after the upgrade with the new scripts (and the old preburn script) and that +/// concurrent preburns are supported immediately without any additional input from TC. We test +/// that the old `burn` and `cancel_burn` scripts will fail after the upgrade though. +#[test] +fn concurrent_preburns_test_upgrade_new_data_new_df_old_scripts_fail() { + let (mut executor, dr_account, tc_account, dd_account) = utils::start_with_released_df(); + let mut tc_seqno = 0; + let mut dd_seqno = 0; + let mut dr_seqno = 1; + executor.set_golden_file(current_function_name!()); + + create_preburn_balance(&mut executor, &dd_account, 10, &mut dd_seqno, false); + burn_old(&mut executor, &tc_account, &mut tc_seqno, false); + + create_preburn_balance(&mut executor, &dd_account, 10, &mut dd_seqno, false); + cancel_burn_old(&mut executor, &tc_account, &mut tc_seqno, false); + + // Upgrade the DF + utils::upgrade_df(&mut executor, &dr_account, &mut dr_seqno, Some(2)); + + // Now make sure that we can upgrade the DD + create_preburn_balance(&mut executor, &dd_account, 100, &mut dd_seqno, false); + // the old scripts will now fail with a `MISCELLANEOUS_ERROR` + assert_eq!( + burn_old(&mut executor, &tc_account, &mut tc_seqno, true) + .unwrap() + .status() + .status() + .unwrap(), + KeptVMStatus::MiscellaneousError + ); + + assert_eq!( + cancel_burn_old(&mut executor, &tc_account, &mut tc_seqno, true) + .unwrap() + .status() + .status() + .unwrap(), + KeptVMStatus::MiscellaneousError + ); +} + +/// Test that the new scripts with the old DF framework will fail. These will not work for multiple +/// reasons, but the first to catch is the gating on script functions. +#[test] +fn concurrent_preburns_old_data_old_df_new_scripts() { + let (mut executor, _, tc_account, _) = utils::start_with_released_df(); + let mut tc_seqno = 0; + executor.set_golden_file(current_function_name!()); + + // The new burn/cancel burn scripts will fail since the preburn hasn't been upgraded yet + assert!(matches!( + cancel_burn_with_amount_new(&mut executor, 100, &tc_account, &mut tc_seqno, true) + .unwrap() + .status() + .status() + .unwrap_err(), + DiscardedVMStatus::FEATURE_UNDER_GATING + )); + assert!(matches!( + burn_with_amount_new(&mut executor, 100, &tc_account, &mut tc_seqno, true) + .unwrap() + .status() + .status() + .unwrap_err(), + DiscardedVMStatus::FEATURE_UNDER_GATING + )); +} diff --git a/vm/e2e-testsuite/src/tests/rotate_key.rs b/vm/e2e-testsuite/src/tests/rotate_key.rs new file mode 100644 index 0000000000..7a5269c718 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/rotate_key.rs @@ -0,0 +1,140 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use starcoin_crypto::{ + ed25519::Ed25519PrivateKey, + multi_ed25519::{MultiEd25519PublicKey, MultiEd25519Signature}, + PrivateKey, SigningKey, Uniform, +}; +use diem_keygen::KeyGen; +use diem_types::{ + transaction::{authenticator::AuthenticationKey, SignedTransaction, TransactionStatus}, + vm_status::{KeptVMStatus, StatusCode}, +}; +use starcoin_language_e2e_tests::{ + account, + common_transactions::{raw_rotate_key_txn, rotate_key_txn}, + test_with_different_versions, + versioning::CURRENT_RELEASE_VERSIONS, +}; + +#[test] +fn rotate_ed25519_key() { + let balance = 1_000_000; + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + // create and publish sender + let mut sender = executor.create_raw_account_data(balance, 10); + executor.add_account_data(&sender); + + let privkey = Ed25519PrivateKey::generate_for_testing(); + let pubkey = privkey.public_key(); + let new_key_hash = AuthenticationKey::ed25519(&pubkey).to_vec(); + let txn = rotate_key_txn(sender.account(), new_key_hash.clone(), 10); + + // execute transaction + let output = &executor.execute_transaction(txn); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed), + ); + executor.apply_write_set(output.write_set()); + + // Check that numbers in store are correct. + let updated_sender = executor + .read_account_resource(sender.account()) + .expect("sender must exist"); + let updated_sender_balance = executor + .read_balance_resource(sender.account(), account::xus_currency_code()) + .expect("sender balance must exist"); + assert_eq!(new_key_hash, updated_sender.authentication_key().to_vec()); + assert_eq!(balance, updated_sender_balance.coin()); + assert_eq!(11, updated_sender.sequence_number()); + + // Check that transactions cannot be sent with the old key any more. + let old_key_txn = rotate_key_txn(sender.account(), vec![], 11); + let old_key_output = &executor.execute_transaction(old_key_txn); + assert_eq!( + old_key_output.status(), + &TransactionStatus::Discard(StatusCode::INVALID_AUTH_KEY), + ); + + // Check that transactions can be sent with the new key. + sender.rotate_key(privkey, pubkey); + let new_key_txn = rotate_key_txn(sender.account(), new_key_hash, 11); + let new_key_output = &executor.execute_transaction(new_key_txn); + assert_eq!( + new_key_output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed), + ); + } + } +} + +#[test] +fn rotate_ed25519_multisig_key() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + let mut seq_number = 10; + // create and publish sender + let sender = executor.create_raw_account_data(1_000_000, seq_number); + executor.add_account_data(&sender); + let _sender_address = sender.address(); + + // create a 1-of-2 multisig policy + let mut keygen = KeyGen::from_seed([9u8; 32]); + + let (privkey1, pubkey1) = keygen.generate_keypair(); + let (privkey2, pubkey2) = keygen.generate_keypair(); + let threshold = 1; + let multi_ed_public_key = + MultiEd25519PublicKey::new(vec![pubkey1, pubkey2], threshold).unwrap(); + let new_auth_key = AuthenticationKey::multi_ed25519(&multi_ed_public_key); + + // (1) rotate key to multisig + let output = &executor.execute_transaction(rotate_key_txn( + sender.account(), + new_auth_key.to_vec(), + seq_number, + )); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed), + ); + executor.apply_write_set(output.write_set()); + seq_number += 1; + + // (2) send a tx signed by privkey 1 + let txn1 = raw_rotate_key_txn(sender.account(), new_auth_key.to_vec(), seq_number); + let signature1 = MultiEd25519Signature::from(privkey1.sign(&txn1)); + let signed_txn1 = + SignedTransaction::new_multisig(txn1, multi_ed_public_key.clone(), signature1); + let output = &executor.execute_transaction(signed_txn1); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed), + ); + executor.apply_write_set(output.write_set()); + seq_number += 1; + + // (3) send a tx signed by privkey 2 + let txn2 = raw_rotate_key_txn(sender.account(), new_auth_key.to_vec(), seq_number); + let pubkey_index = 1; + let signature2 = + MultiEd25519Signature::new(vec![(privkey2.sign(&txn2), pubkey_index)]).unwrap(); + let signed_txn2 = SignedTransaction::new_multisig(txn2, multi_ed_public_key, signature2); + signed_txn2.clone().check_signature().unwrap(); + let output = &executor.execute_transaction(signed_txn2); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed), + ); + } + } +} + +#[test] + +fn rotate_shared_ed25519_public_key() {} diff --git a/vm/e2e-testsuite/src/tests/script_functions.rs b/vm/e2e-testsuite/src/tests/script_functions.rs new file mode 100644 index 0000000000..774544965f --- /dev/null +++ b/vm/e2e-testsuite/src/tests/script_functions.rs @@ -0,0 +1,186 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use diem_types::{ + on_chain_config::DIEM_VERSION_2, + transaction::{ScriptFunction, TransactionStatus}, + vm_status::{DiscardedVMStatus, KeptVMStatus}, +}; +use move_core_types::{identifier::Identifier, language_storage::ModuleId}; +use starcoin_language_e2e_tests::{ + account::Account, compile::compile_module, current_function_name, executor::FakeExecutor, + transaction_status_eq, utils, +}; + +fn prepare_module(executor: &mut FakeExecutor, account: &Account, seq_num: u64) -> u64 { + let program = format!( + " + module 0x{}.M {{ + f_private(s: &signer) {{ + label b0: + return; + }} + + public f_public(s: &signer) {{ + label b0: + return; + }} + + public(script) f_script(s: signer) {{ + label b0: + return; + }} + }} + ", + account.address(), + ); + let compiled_module = compile_module(&program).1; + + let txn = account + .transaction() + .module(compiled_module) + .sequence_number(seq_num) + .sign(); + + let output = executor.execute_transaction(txn); + // module publishing should always succeed + assert!(transaction_status_eq( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed), + )); + executor.apply_write_set(output.write_set()); + + seq_num + 1 +} + +#[test] +fn script_fn_payload_invoke_private_fn() { + let (mut executor, dr_account, _, _) = utils::start_with_released_df(); + let mut dr_seqno = 1; + executor.set_golden_file(current_function_name!()); + + let sequence_number = 2; + let account = executor.create_raw_account_data(1_000_000, sequence_number); + executor.add_account_data(&account); + + let sequence_number = prepare_module(&mut executor, account.account(), sequence_number); + let txn = account + .account() + .transaction() + .script_function(ScriptFunction::new( + ModuleId::new(*account.address(), Identifier::new("M").unwrap()), + Identifier::new("f_private").unwrap(), + vec![], + vec![], + )) + .sequence_number(sequence_number) + .sign(); + + let output = executor.execute_transaction(txn.clone()); + assert!(transaction_status_eq( + output.status(), + &TransactionStatus::Discard(DiscardedVMStatus::FEATURE_UNDER_GATING), + )); + + // enable the feature + utils::upgrade_df( + &mut executor, + &dr_account, + &mut dr_seqno, + Some(DIEM_VERSION_2.major), + ); + + let output = executor.execute_transaction(txn); + assert!(transaction_status_eq( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::MiscellaneousError), + )); +} + +#[test] +fn script_fn_payload_invoke_public_fn() { + let (mut executor, dr_account, _, _) = utils::start_with_released_df(); + let mut dr_seqno = 1; + executor.set_golden_file(current_function_name!()); + + let sequence_number = 2; + let account = executor.create_raw_account_data(1_000_000, sequence_number); + executor.add_account_data(&account); + + let sequence_number = prepare_module(&mut executor, account.account(), sequence_number); + let txn = account + .account() + .transaction() + .script_function(ScriptFunction::new( + ModuleId::new(*account.address(), Identifier::new("M").unwrap()), + Identifier::new("f_public").unwrap(), + vec![], + vec![], + )) + .sequence_number(sequence_number) + .sign(); + + let output = executor.execute_transaction(txn.clone()); + assert!(transaction_status_eq( + output.status(), + &TransactionStatus::Discard(DiscardedVMStatus::FEATURE_UNDER_GATING), + )); + + // enable the feature + utils::upgrade_df( + &mut executor, + &dr_account, + &mut dr_seqno, + Some(DIEM_VERSION_2.major), + ); + + let output = executor.execute_transaction(txn); + assert!(transaction_status_eq( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::MiscellaneousError), + )); +} + +#[test] +fn script_fn_payload_invoke_script_fn() { + let (mut executor, dr_account, _, _) = utils::start_with_released_df(); + let mut dr_seqno = 1; + executor.set_golden_file(current_function_name!()); + + let sequence_number = 2; + let account = executor.create_raw_account_data(1_000_000, sequence_number); + executor.add_account_data(&account); + + let sequence_number = prepare_module(&mut executor, account.account(), sequence_number); + let txn = account + .account() + .transaction() + .script_function(ScriptFunction::new( + ModuleId::new(*account.address(), Identifier::new("M").unwrap()), + Identifier::new("f_script").unwrap(), + vec![], + vec![], + )) + .sequence_number(sequence_number) + .sign(); + + let output = executor.execute_transaction(txn.clone()); + assert!(transaction_status_eq( + output.status(), + &TransactionStatus::Discard(DiscardedVMStatus::FEATURE_UNDER_GATING), + )); + + // enable the feature + utils::upgrade_df( + &mut executor, + &dr_account, + &mut dr_seqno, + Some(DIEM_VERSION_2.major), + ); + + let output = executor.execute_transaction(txn); + assert!(transaction_status_eq( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed), + )); +} diff --git a/vm/e2e-testsuite/src/tests/scripts.rs b/vm/e2e-testsuite/src/tests/scripts.rs new file mode 100644 index 0000000000..85735a633d --- /dev/null +++ b/vm/e2e-testsuite/src/tests/scripts.rs @@ -0,0 +1,426 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use diem_types::{ + account_address::AccountAddress, + account_config, + on_chain_config::VMPublishingOption, + transaction::{Script, TransactionStatus}, + vm_status::KeptVMStatus, +}; +use move_binary_format::file_format::{ + empty_script, AbilitySet, AddressIdentifierIndex, Bytecode, FunctionHandle, + FunctionHandleIndex, IdentifierIndex, ModuleHandle, ModuleHandleIndex, SignatureIndex, +}; +use move_core_types::{ + identifier::Identifier, + language_storage::{StructTag, TypeTag}, +}; +use starcoin_language_e2e_tests::{account, current_function_name, executor::FakeExecutor}; + +#[test] +fn script_code_unverifiable() { + let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + executor.set_golden_file(current_function_name!()); + + // create and publish sender + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + // create a bogus script + let mut script = empty_script(); + script.code.code = vec![Bytecode::LdU8(0), Bytecode::Add, Bytecode::Ret]; + let mut blob = vec![]; + script.serialize(&mut blob).expect("script must serialize"); + let txn = sender + .account() + .transaction() + .script(Script::new(blob, vec![], vec![])) + .sequence_number(10) + .gas_unit_price(1) + .sign(); + // execute transaction + let output = &executor.execute_transaction(txn); + let status = output.status(); + match status { + TransactionStatus::Keep(_) => (), + _ => panic!("TransactionStatus must be Keep"), + } + assert_eq!( + status.status(), + // StatusCode::NEGATIVE_STACK_SIZE_WITHIN_BLOCK + Ok(KeptVMStatus::MiscellaneousError) + ); + executor.apply_write_set(output.write_set()); + + // Check that numbers in store are correct. + let gas = output.gas_used(); + let balance = 1_000_000 - gas; + let updated_sender = executor + .read_account_resource(sender.account()) + .expect("sender must exist"); + let updated_sender_balance = executor + .read_balance_resource(sender.account(), account::xus_currency_code()) + .expect("sender balance must exist"); + assert_eq!(balance, updated_sender_balance.coin()); + assert_eq!(11, updated_sender.sequence_number()); +} + +#[test] +fn script_none_existing_module_dep() { + let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + executor.set_golden_file(current_function_name!()); + + // create and publish sender + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + // create a bogus script + let mut script = empty_script(); + + // make a non existent external module + script + .address_identifiers + .push(AccountAddress::new([2u8; AccountAddress::LENGTH])); + script.identifiers.push(Identifier::new("module").unwrap()); + let module_handle = ModuleHandle { + address: AddressIdentifierIndex((script.address_identifiers.len() - 1) as u16), + name: IdentifierIndex((script.identifiers.len() - 1) as u16), + }; + script.module_handles.push(module_handle); + // make a non existent function on the non existent external module + script.identifiers.push(Identifier::new("foo").unwrap()); + let fun_handle = FunctionHandle { + module: ModuleHandleIndex((script.module_handles.len() - 1) as u16), + name: IdentifierIndex((script.identifiers.len() - 1) as u16), + parameters: SignatureIndex(0), + return_: SignatureIndex(0), + type_parameters: vec![], + }; + script.function_handles.push(fun_handle); + + script.code.code = vec![ + Bytecode::Call(FunctionHandleIndex( + (script.function_handles.len() - 1) as u16, + )), + Bytecode::Ret, + ]; + let mut blob = vec![]; + script.serialize(&mut blob).expect("script must serialize"); + let txn = sender + .account() + .transaction() + .script(Script::new(blob, vec![], vec![])) + .sequence_number(10) + .gas_unit_price(1) + .sign(); + + // execute transaction + let output = &executor.execute_transaction(txn); + let status = output.status(); + match status { + TransactionStatus::Keep(_) => (), + _ => panic!("TransactionStatus must be Keep"), + } + assert_eq!( + status.status(), + //StatusCode::LINKER_ERROR + Ok(KeptVMStatus::MiscellaneousError) + ); + executor.apply_write_set(output.write_set()); + + // Check that numbers in store are correct. + let gas = output.gas_used(); + let balance = 1_000_000 - gas; + let updated_sender = executor + .read_account_resource(sender.account()) + .expect("sender must exist"); + let updated_sender_balance = executor + .read_balance_resource(sender.account(), account::xus_currency_code()) + .expect("sender balance must exist"); + assert_eq!(balance, updated_sender_balance.coin()); + assert_eq!(11, updated_sender.sequence_number()); +} + +#[test] +fn script_non_existing_function_dep() { + let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + executor.set_golden_file(current_function_name!()); + + // create and publish sender + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + // create a bogus script + let mut script = empty_script(); + + // BCS module + script + .address_identifiers + .push(account_config::CORE_CODE_ADDRESS); + script.identifiers.push(Identifier::new("BCS").unwrap()); + let module_handle = ModuleHandle { + address: AddressIdentifierIndex((script.address_identifiers.len() - 1) as u16), + name: IdentifierIndex((script.identifiers.len() - 1) as u16), + }; + script.module_handles.push(module_handle); + // make a non existent function on BCS + script.identifiers.push(Identifier::new("foo").unwrap()); + let fun_handle = FunctionHandle { + module: ModuleHandleIndex((script.module_handles.len() - 1) as u16), + name: IdentifierIndex((script.identifiers.len() - 1) as u16), + parameters: SignatureIndex(0), + return_: SignatureIndex(0), + type_parameters: vec![], + }; + script.function_handles.push(fun_handle); + + script.code.code = vec![ + Bytecode::Call(FunctionHandleIndex( + (script.function_handles.len() - 1) as u16, + )), + Bytecode::Ret, + ]; + let mut blob = vec![]; + script.serialize(&mut blob).expect("script must serialize"); + let txn = sender + .account() + .transaction() + .script(Script::new(blob, vec![], vec![])) + .sequence_number(10) + .gas_unit_price(1) + .sign(); + + // execute transaction + let output = &executor.execute_transaction(txn); + let status = output.status(); + match status { + TransactionStatus::Keep(_) => (), + _ => panic!("TransactionStatus must be Keep"), + } + assert_eq!( + status.status(), + // StatusCode::LOOKUP_FAILED + Ok(KeptVMStatus::MiscellaneousError) + ); + executor.apply_write_set(output.write_set()); + + // Check that numbers in store are correct. + let gas = output.gas_used(); + let balance = 1_000_000 - gas; + let updated_sender = executor + .read_account_resource(sender.account()) + .expect("sender must exist"); + let updated_sender_balance = executor + .read_balance_resource(sender.account(), account::xus_currency_code()) + .expect("sender balance must exist"); + assert_eq!(balance, updated_sender_balance.coin()); + assert_eq!(11, updated_sender.sequence_number()); +} + +#[test] +fn script_bad_sig_function_dep() { + let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + executor.set_golden_file(current_function_name!()); + + // create and publish sender + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + // create a bogus script + let mut script = empty_script(); + + // BCS module + script + .address_identifiers + .push(account_config::CORE_CODE_ADDRESS); + script.identifiers.push(Identifier::new("BCS").unwrap()); + let module_handle = ModuleHandle { + address: AddressIdentifierIndex((script.address_identifiers.len() - 1) as u16), + name: IdentifierIndex((script.identifiers.len() - 1) as u16), + }; + script.module_handles.push(module_handle); + // BCS::to_bytes with bad sig + script + .identifiers + .push(Identifier::new("to_bytes").unwrap()); + let fun_handle = FunctionHandle { + module: ModuleHandleIndex((script.module_handles.len() - 1) as u16), + name: IdentifierIndex((script.identifiers.len() - 1) as u16), + parameters: SignatureIndex(0), + return_: SignatureIndex(0), + type_parameters: vec![], + }; + script.function_handles.push(fun_handle); + + script.code.code = vec![ + Bytecode::Call(FunctionHandleIndex( + (script.function_handles.len() - 1) as u16, + )), + Bytecode::Ret, + ]; + let mut blob = vec![]; + script.serialize(&mut blob).expect("script must serialize"); + let txn = sender + .account() + .transaction() + .script(Script::new(blob, vec![], vec![])) + .sequence_number(10) + .gas_unit_price(1) + .sign(); + // execute transaction + let output = &executor.execute_transaction(txn); + let status = output.status(); + match status { + TransactionStatus::Keep(_) => (), + _ => panic!("TransactionStatus must be Keep"), + } + assert_eq!( + status.status(), + // StatusCode::TYPE_MISMATCH + Ok(KeptVMStatus::MiscellaneousError) + ); + executor.apply_write_set(output.write_set()); + + // Check that numbers in store are correct. + let gas = output.gas_used(); + let balance = 1_000_000 - gas; + let updated_sender = executor + .read_account_resource(sender.account()) + .expect("sender must exist"); + let updated_sender_balance = executor + .read_balance_resource(sender.account(), account::xus_currency_code()) + .expect("sender balance must exist"); + assert_eq!(balance, updated_sender_balance.coin()); + assert_eq!(11, updated_sender.sequence_number()); +} + +#[test] +fn script_type_argument_module_does_not_exist() { + let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + executor.set_golden_file(current_function_name!()); + + // create and publish sender + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + // create a bogus script + let mut script = empty_script(); + + // make a non existent external module + let address = AccountAddress::new([2u8; AccountAddress::LENGTH]); + let module = Identifier::new("module").unwrap(); + script.address_identifiers.push(address); + script.identifiers.push(module.clone()); + let module_handle = ModuleHandle { + address: AddressIdentifierIndex((script.address_identifiers.len() - 1) as u16), + name: IdentifierIndex((script.identifiers.len() - 1) as u16), + }; + script.module_handles.push(module_handle); + script.code.code = vec![Bytecode::Ret]; + script.type_parameters = vec![AbilitySet::EMPTY]; + let mut blob = vec![]; + script.serialize(&mut blob).expect("script must serialize"); + let txn = sender + .account() + .transaction() + .script(Script::new( + blob, + vec![TypeTag::Struct(StructTag { + address, + module, + name: Identifier::new("fake").unwrap(), + type_params: vec![], + })], + vec![], + )) + .sequence_number(10) + .gas_unit_price(1) + .sign(); + + // execute transaction + let output = &executor.execute_transaction(txn); + let status = output.status(); + assert_eq!( + status, + &TransactionStatus::Keep(KeptVMStatus::MiscellaneousError) + ); + executor.apply_write_set(output.write_set()); + + // Check that numbers in store are correct. + let gas = output.gas_used(); + let balance = 1_000_000 - gas; + let updated_sender = executor + .read_account_resource(sender.account()) + .expect("sender must exist"); + let updated_sender_balance = executor + .read_balance_resource(sender.account(), account::xus_currency_code()) + .expect("sender balance must exist"); + assert_eq!(balance, updated_sender_balance.coin()); + assert_eq!(11, updated_sender.sequence_number()); +} + +#[test] +fn script_nested_type_argument_module_does_not_exist() { + let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + executor.set_golden_file(current_function_name!()); + + // create and publish sender + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + // create a bogus script + let mut script = empty_script(); + + // make a non existent external module + let address = AccountAddress::new([2u8; AccountAddress::LENGTH]); + let module = Identifier::new("module").unwrap(); + script.address_identifiers.push(address); + script.identifiers.push(module.clone()); + let module_handle = ModuleHandle { + address: AddressIdentifierIndex((script.address_identifiers.len() - 1) as u16), + name: IdentifierIndex((script.identifiers.len() - 1) as u16), + }; + script.module_handles.push(module_handle); + script.code.code = vec![Bytecode::Ret]; + script.type_parameters = vec![AbilitySet::EMPTY]; + let mut blob = vec![]; + script.serialize(&mut blob).expect("script must serialize"); + let txn = sender + .account() + .transaction() + .script(Script::new( + blob, + vec![TypeTag::Vector(Box::new(TypeTag::Struct(StructTag { + address, + module, + name: Identifier::new("fake").unwrap(), + type_params: vec![], + })))], + vec![], + )) + .sequence_number(10) + .gas_unit_price(1) + .sign(); + + // execute transaction + let output = &executor.execute_transaction(txn); + let status = output.status(); + assert_eq!( + status, + &TransactionStatus::Keep(KeptVMStatus::MiscellaneousError) + ); + executor.apply_write_set(output.write_set()); + + // Check that numbers in store are correct. + let gas = output.gas_used(); + let balance = 1_000_000 - gas; + let updated_sender = executor + .read_account_resource(sender.account()) + .expect("sender must exist"); + let updated_sender_balance = executor + .read_balance_resource(sender.account(), account::xus_currency_code()) + .expect("sender balance must exist"); + assert_eq!(balance, updated_sender_balance.coin()); + assert_eq!(11, updated_sender.sequence_number()); +} diff --git a/vm/e2e-testsuite/src/tests/transaction_builder.rs b/vm/e2e-testsuite/src/tests/transaction_builder.rs new file mode 100644 index 0000000000..8fdb897761 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/transaction_builder.rs @@ -0,0 +1,1268 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +//! Tests for all of the script encoding functions in language/transaction_builder/lib.rs. +//! Thorough tests that exercise all of the behaviors of the script should live in the language +//! functional tests; these tests are only to ensure that the script encoding functions take the +//! correct types + produce a runnable script. + +#![forbid(unsafe_code)] + +use starcoin_crypto::{ed25519::Ed25519PrivateKey, traits::SigningKey, PrivateKey, Uniform}; +// use diem_keygen::KeyGen; +use starcoin_transaction_builder::stdlib::*; +use starcoin_types::{ + account_address::AccountAddress, + account_config, + transaction::{ + authenticator::AuthenticationKey, Script, TransactionOutput, TransactionStatus, + WriteSetPayload, + }, + vm_status::{KeptVMStatus, StatusCode}, +}; +use move_core_types::language_storage::TypeTag; +use starcoin_language_e2e_tests::{ + account::{self, Account}, + common_transactions::rotate_key_txn, + //currencies, current_function_name, + executor::FakeExecutor, + gas_costs, test_with_different_versions, + versioning::CURRENT_RELEASE_VERSIONS, +}; + +const XUS_THRESHOLD: u64 = 10_000_000_000 / 5; +const BAD_METADATA_SIGNATURE_ERROR_CODE: u64 = 775; +const MISMATCHED_METADATA_SIGNATURE_ERROR_CODE: u64 = 1031; +const PAYEE_COMPLIANCE_KEY_NOT_SET_ERROR_CODE: u64 = 1281; + +#[test] +fn test_rotate_authentication_key_with_nonce_admin() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let new_account = executor.create_raw_account_data(100_000, 0); + executor.add_account_data(&new_account); + + let privkey = Ed25519PrivateKey::generate_for_testing(); + let pubkey = privkey.public_key(); + let new_key_hash = AuthenticationKey::ed25519(&pubkey).to_vec(); + + let account = test_env.dr_account; + let txn = account + .transaction() + .write_set(WriteSetPayload::Script { + script: encode_rotate_authentication_key_with_nonce_admin_script(0, new_key_hash.clone()), + execute_as: *new_account.address(), + }) + .sequence_number(test_env.dr_sequence_number) + .sign(); + executor.new_block(); + let output = executor.execute_and_apply(txn); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed), + ); + + let updated_sender = executor + .read_account_resource(new_account.account()) + .expect("sender must exist"); + + assert_eq!(updated_sender.authentication_key(), new_key_hash.as_slice()); + } + } +} + +#[test] +fn freeze_unfreeze_account() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + let account = executor.create_raw_account(); + + let blessed = test_env.tc_account; + + executor.execute_and_apply( + blessed + .transaction() + .script(encode_create_parent_vasp_account_script( + account_config::xus_tag(), + 0, + *account.address(), + account.auth_key_prefix(), + vec![], + true, + )) + .sequence_number(test_env.tc_sequence_number) + .sign(), + ); + + // Execute freeze on account + executor.execute_and_apply( + blessed + .transaction() + .script(encode_freeze_account_script(3, *account.address())) + .sequence_number(test_env.tc_sequence_number.checked_add(1).unwrap()) + .sign(), + ); + + // Attempt rotate key txn from frozen account + let privkey = Ed25519PrivateKey::generate_for_testing(); + let pubkey = privkey.public_key(); + let new_key_hash = AuthenticationKey::ed25519(&pubkey).to_vec(); + let txn = rotate_key_txn(&account, new_key_hash, 0); + + let output = &executor.execute_transaction(txn.clone()); + assert_eq!( + output.status(), + &TransactionStatus::Discard(StatusCode::SENDING_ACCOUNT_FROZEN), + ); + + // Execute unfreeze on account + executor.execute_and_apply( + blessed + .transaction() + .script(encode_unfreeze_account_script(4, *account.address())) + .sequence_number(test_env.tc_sequence_number.checked_add(2).unwrap()) + .sign(), + ); + // execute rotate key transaction from unfrozen account now succeeds + let output = &executor.execute_transaction(txn); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed), + ); + } + } +} + +#[test] +fn create_parent_and_child_vasp() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + let blessed = test_env.tc_account; + let parent = executor.create_raw_account(); + let child = executor.create_raw_account(); + + let mut keygen = KeyGen::from_seed([9u8; 32]); + + // create a parent VASP + let add_all_currencies = false; + executor.execute_and_apply( + blessed + .transaction() + .script(encode_create_parent_vasp_account_script( + account_config::xus_tag(), + 0, + *parent.address(), + parent.auth_key_prefix(), + vec![], + add_all_currencies, + )) + .sequence_number(test_env.tc_sequence_number) + .sign(), + ); + + // create a child VASP with a zero balance + executor.execute_and_apply( + parent + .transaction() + .script(encode_create_child_vasp_account_script( + account_config::xus_tag(), + *child.address(), + child.auth_key_prefix(), + add_all_currencies, + 0, + )) + .sequence_number(0) + .sign(), + ); + // check for zero balance + assert_eq!( + executor + .read_balance_resource(&child, account::xus_currency_code()) + .unwrap() + .coin(), + 0 + ); + + let (_, new_compliance_public_key) = keygen.generate_keypair(); + // rotate parent's base_url and compliance public key + executor.execute_and_apply( + parent + .transaction() + .script(encode_rotate_dual_attestation_info_script( + b"new_name".to_vec(), + new_compliance_public_key.to_bytes().to_vec(), + )) + .sequence_number(1) + .sign(), + ); + } + } +} + +#[test] +fn create_child_vasp_all_currencies() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + let blessed = test_env.tc_account; + let dd = test_env.dd_account; + let parent = executor.create_raw_account(); + let child = executor.create_raw_account(); + + // create a parent VASP + let add_all_currencies = true; + executor.execute_and_apply( + blessed + .transaction() + .script(encode_create_parent_vasp_account_script( + account_config::xus_tag(), + 0, + *parent.address(), + parent.auth_key_prefix(), + vec![], + add_all_currencies, + )) + .sequence_number(test_env.tc_sequence_number) + .sign(), + ); + + let amount = 100; + // mint to the parent VASP + executor.execute_and_apply( + dd.transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *parent.address(), + amount, + vec![], + vec![], + )) + .sequence_number(0) + .sign(), + ); + + assert!(executor + .read_balance_resource(&parent, account::xus_currency_code()) + .is_some()); + + // create a child VASP with a balance of amount + executor.execute_and_apply( + parent + .transaction() + .script(encode_create_child_vasp_account_script( + account_config::xus_tag(), + *child.address(), + child.auth_key_prefix(), + add_all_currencies, + amount, + )) + .sequence_number(0) + .max_gas_amount(gas_costs::TXN_RESERVED * 3) + .sign(), + ); + + assert!(executor + .read_balance_resource(&parent, account::xus_currency_code()) + .is_some()); + } + } +} + +#[test] +fn create_child_vasp_with_balance() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + let blessed = test_env.tc_account; + let dd = test_env.dd_account; + let parent = executor.create_raw_account(); + let child = executor.create_raw_account(); + + // create a parent VASP + let add_all_currencies = true; + executor.execute_and_apply( + blessed + .transaction() + .script(encode_create_parent_vasp_account_script( + account_config::xus_tag(), + 0, + *parent.address(), + parent.auth_key_prefix(), + vec![], + add_all_currencies, + )) + .sequence_number(test_env.tc_sequence_number) + .sign(), + ); + + let amount = 100; + // mint to the parent VASP + executor.execute_and_apply( + dd.transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *parent.address(), + amount, + vec![], + vec![], + )) + .sequence_number(0) + .sign(), + ); + + assert_eq!( + executor + .read_balance_resource(&parent, account::xus_currency_code()) + .unwrap() + .coin(), + amount + ); + + // create a child VASP with a balance of amount + executor.execute_and_apply( + parent + .transaction() + .script(encode_create_child_vasp_account_script( + account_config::xus_tag(), + *child.address(), + child.auth_key_prefix(), + add_all_currencies, + amount, + )) + .sequence_number(0) + .max_gas_amount(gas_costs::TXN_RESERVED * 3) + .sign(), + ); + + // check balance + assert_eq!( + executor + .read_balance_resource(&child, account::xus_currency_code()) + .unwrap() + .coin(), + amount + ); + } + } +} + +#[test] +fn dual_attestation_payment() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + // account that will receive the dual attestation payment + let payment_receiver = executor.create_raw_account(); + let payment_sender = executor.create_raw_account(); + let sender_child = executor.create_raw_account(); + let payee_child = executor.create_raw_account(); + let blessed = test_env.tc_account; + let dd = test_env.dd_account; + let mut keygen = KeyGen::from_seed([9u8; 32]); + let (sender_vasp_compliance_private_key, _) = keygen.generate_keypair(); + let (receiver_vasp_compliance_private_key, receiver_vasp_compliance_public_key) = + keygen.generate_keypair(); + + let payment_amount = XUS_THRESHOLD; + + executor.execute_and_apply( + blessed + .transaction() + .script(encode_create_parent_vasp_account_script( + account_config::xus_tag(), + 0, + *payment_sender.address(), + payment_sender.auth_key_prefix(), + vec![], + false, + )) + .sequence_number(test_env.tc_sequence_number) + .sign(), + ); + + executor.execute_and_apply( + blessed + .transaction() + .script(encode_create_parent_vasp_account_script( + account_config::xus_tag(), + 0, + *payment_receiver.address(), + payment_receiver.auth_key_prefix(), + vec![], + false, + )) + .sequence_number(test_env.tc_sequence_number.checked_add(1).unwrap()) + .sign(), + ); + + // set the dual attestation info for the receiver + executor.execute_and_apply( + payment_receiver + .transaction() + .script(encode_rotate_dual_attestation_info_script( + b"any base_url works".to_vec(), + receiver_vasp_compliance_public_key.to_bytes().to_vec(), + )) + .sequence_number(0) + .sign(), + ); + + executor.execute_and_apply( + dd.transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *payment_sender.address(), + XUS_THRESHOLD * 10, + vec![], + vec![], + )) + .sequence_number(0) + .sign(), + ); + + // create a child VASP with a balance of amount + executor.execute_and_apply( + payment_sender + .transaction() + .script(encode_create_child_vasp_account_script( + account_config::xus_tag(), + *sender_child.address(), + sender_child.auth_key_prefix(), + false, + 10, + )) + .sequence_number(0) + .sign(), + ); + + // create a child VASP for the payee too + executor.execute_and_apply( + payment_receiver + .transaction() + .script(encode_create_child_vasp_account_script( + account_config::xus_tag(), + *payee_child.address(), + payee_child.auth_key_prefix(), + false, + 0, + )) + .sequence_number(1) + .sign(), + ); + { + // Transaction >= 1_000_000 threshold goes through signature verification with valid signature, passes + // Do the offline protocol: generate a payment id, sign with the receiver's private key, include + // in transaction from sender's account + let ref_id = bcs::to_bytes(&7777u64).unwrap(); + let output = executor.execute_and_apply( + payment_sender + .transaction() + .script(create_dual_attestation_payment( + *payment_sender.address(), + *payment_receiver.address(), + payment_amount, + account_config::xus_tag(), + ref_id, + &receiver_vasp_compliance_private_key, + )) + .sequence_number(1) + .sign(), + ); + assert_eq!(output.status().status(), Ok(KeptVMStatus::Executed)); + } + { + // Transaction >= 1_000_000 threshold goes through signature verification with valid signature, passes + // Do the offline protocol: generate a payment id, sign with the receiver's private key, include + // in transaction from sender's account. Make sure credential resolution is working for + // children. + let ref_id = bcs::to_bytes(&7777u64).unwrap(); + let output = executor.execute_and_apply( + payment_sender + .transaction() + .script(create_dual_attestation_payment( + *payment_sender.address(), + *payee_child.address(), + payment_amount, + account_config::xus_tag(), + ref_id, + &receiver_vasp_compliance_private_key, + )) + .sequence_number(2) + .sign(), + ); + assert_eq!(output.status().status(), Ok(KeptVMStatus::Executed)); + } + { + // transaction >= 1_000_000 (set in DualAttestation.move) threshold goes through signature verification but has an + // structurally invalid signature. Fails. + let ref_id = [0u8; 32].to_vec(); + let output = executor.execute_transaction( + payment_sender + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *payment_receiver.address(), + payment_amount, + ref_id, + b"invalid signature".to_vec(), + )) + .sequence_number(3) + .sign(), + ); + + assert!(matches!( + output.status().status(), + Ok(KeptVMStatus::MoveAbort( + _, + BAD_METADATA_SIGNATURE_ERROR_CODE + )) + )); + } + + { + // transaction >= 1_000_000 threshold goes through signature verification with invalid signature, aborts + let ref_id = bcs::to_bytes(&9999u64).unwrap(); + let output = executor.execute_transaction( + payment_sender + .transaction() + .script(create_dual_attestation_payment( + *payment_sender.address(), + *payment_receiver.address(), + payment_amount, + account_config::xus_tag(), + ref_id, + // Sign with the wrong private key + &sender_vasp_compliance_private_key, + )) + .sequence_number(3) + .sign(), + ); + + assert_aborted_with(output, MISMATCHED_METADATA_SIGNATURE_ERROR_CODE); + } + + { + // similar, but with empty payment ID (make sure signature is still invalid!) + let ref_id = vec![]; + let output = executor.execute_transaction( + payment_sender + .transaction() + .script(create_dual_attestation_payment( + *payment_sender.address(), + *payment_receiver.address(), + payment_amount, + account_config::xus_tag(), + ref_id, + &sender_vasp_compliance_private_key, + )) + .sequence_number(3) + .sign(), + ); + assert_aborted_with(output, MISMATCHED_METADATA_SIGNATURE_ERROR_CODE); + } + { + // Intra-VASP transaction >= 1000 threshold, should go through with any signature since + // checking isn't performed on intra-vasp transfers + // parent->child + executor.execute_and_apply( + payment_sender + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *sender_child.address(), + payment_amount * 2, + vec![0], + vec![], + )) + .sequence_number(3) + .sign(), + ); + + // However, should still fail if we opt-in to dual attestation with a bad signature + let output = executor.execute_transaction( + payment_sender + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *sender_child.address(), + payment_amount * 2, + vec![0], + b"invalid signature".to_vec(), + )) + .sequence_number(4) + .sign(), + ); + assert_aborted_with(output, BAD_METADATA_SIGNATURE_ERROR_CODE) + } + { + // Checking isn't performed on intra-vasp transfers + // child->parent + executor.execute_and_apply( + sender_child + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *payment_sender.address(), + payment_amount, + vec![0], + vec![], + )) + .sequence_number(0) + .sign(), + ); + } + { + // Checking isn't performed on intra-vasp transfers (self payment) + executor.execute_and_apply( + sender_child + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *sender_child.address(), + payment_amount, + vec![0], + vec![], + )) + .sequence_number(1) + .sign(), + ); + } + { + // Rotate the parent VASP's compliance key and base URL + let (_, new_compliance_public_key) = keygen.generate_keypair(); + executor.execute_and_apply( + payment_receiver + .transaction() + .script(encode_rotate_dual_attestation_info_script( + b"any base_url works".to_vec(), + new_compliance_public_key.to_bytes().to_vec(), + )) + .sequence_number(2) + .sign(), + ); + } + { + // This previously succeeded, but should now fail since their public key has changed + // in transaction from sender's account. This tests to make sure their public key was + // rotated. + let output = executor.execute_transaction( + payment_sender + .transaction() + .script(create_dual_attestation_payment( + *payment_sender.address(), + *payment_receiver.address(), + payment_amount, + account_config::xus_tag(), + // pick an arbitrary ref_id + bcs::to_bytes(&9999u64).unwrap(), + &receiver_vasp_compliance_private_key, + )) + .sequence_number(4) + .sign(), + ); + assert_aborted_with(output, MISMATCHED_METADATA_SIGNATURE_ERROR_CODE) + } + { + // trying to send a tx to a recipient who has not set up dual attestation should fail + let output = executor.execute_transaction( + payment_receiver + .transaction() + .script(create_dual_attestation_payment( + *payment_receiver.address(), + *payment_sender.address(), + payment_amount, + account_config::xus_tag(), + // pick an arbitrary ref_id + bcs::to_bytes(&9999u64).unwrap(), + &receiver_vasp_compliance_private_key, + )) + .sequence_number(3) + .sign(), + ); + assert_aborted_with(output, PAYEE_COMPLIANCE_KEY_NOT_SET_ERROR_CODE) + } + } + } +} + +fn create_dual_attestation_payment( + sender_address: AccountAddress, + receiver_address: AccountAddress, + amount: u64, + coin_type: TypeTag, + ref_id: Vec, + receiver_compliance_private_key: &Ed25519PrivateKey, +) -> Script { + let mut domain_separator = b"@@$$DIEM_ATTEST$$@@".to_vec(); + let message = { + let mut msg = ref_id.clone(); + msg.append(&mut bcs::to_bytes(&sender_address).unwrap()); + msg.append(&mut bcs::to_bytes(&amount).unwrap()); + msg.append(&mut domain_separator); + msg + }; + let signature = ::sign_arbitrary_message( + receiver_compliance_private_key, + &message, + ); + encode_peer_to_peer_with_metadata_script( + coin_type, + receiver_address, + amount, + ref_id, + signature.to_bytes().to_vec(), + ) +} + +fn assert_aborted_with(output: TransactionOutput, error_code: u64) { + if let Ok(KeptVMStatus::MoveAbort(_, code)) = output.status().status() { + assert_eq!(error_code, code); + } else { + assert!(matches!( + output.status().status(), + Ok(KeptVMStatus::MoveAbort(..)) + )); + } +} + +// Check that DD <-> DD and DD <-> VASP payments over the threshold work with and without dual attesation. +#[test] +fn dd_dual_attestation_payments() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + // account that will receive the dual attestation payment + let parent_vasp = executor.create_raw_account(); + let dd1 = executor.create_raw_account(); + let dd2 = executor.create_raw_account(); + let blessed = test_env.tc_account; + let mint_dd = test_env.dd_account; + let mut keygen = KeyGen::from_seed([9u8; 32]); + let (parent_vasp_compliance_private_key, parent_vasp_compliance_public_key) = + keygen.generate_keypair(); + let (dd1_compliance_private_key, dd1_compliance_public_key) = keygen.generate_keypair(); + let (dd2_compliance_private_key, dd2_compliance_public_key) = keygen.generate_keypair(); + + // create the VASP account + executor.execute_and_apply( + blessed + .transaction() + .script(encode_create_parent_vasp_account_script( + account_config::xus_tag(), + 0, + *parent_vasp.address(), + parent_vasp.auth_key_prefix(), + vec![], + false, + )) + .sequence_number(test_env.tc_sequence_number) + .sign(), + ); + // create the DD1 account + executor.execute_and_apply( + blessed + .transaction() + .script(encode_create_designated_dealer_script( + account_config::xus_tag(), + 0, + *dd1.address(), + dd1.auth_key_prefix(), + vec![], + false, + )) + .sequence_number(test_env.tc_sequence_number.checked_add(1).unwrap()) + .sign(), + ); + // create the DD2 account + executor.execute_and_apply( + blessed + .transaction() + .script(encode_create_designated_dealer_script( + account_config::xus_tag(), + 0, + *dd2.address(), + dd2.auth_key_prefix(), + vec![], + false, + )) + .sequence_number(test_env.tc_sequence_number.checked_add(2).unwrap()) + .sign(), + ); + + // set up dual attestation info for VASP, DD1, DD2 + executor.execute_and_apply( + parent_vasp + .transaction() + .script(encode_rotate_dual_attestation_info_script( + b"any base_url works".to_vec(), + parent_vasp_compliance_public_key.to_bytes().to_vec(), + )) + .sequence_number(0) + .sign(), + ); + executor.execute_and_apply( + dd1.transaction() + .script(encode_rotate_dual_attestation_info_script( + b"any base_url works".to_vec(), + dd1_compliance_public_key.to_bytes().to_vec(), + )) + .sequence_number(0) + .sign(), + ); + executor.execute_and_apply( + dd2.transaction() + .script(encode_rotate_dual_attestation_info_script( + b"any base_url works".to_vec(), + dd2_compliance_public_key.to_bytes().to_vec(), + )) + .sequence_number(0) + .sign(), + ); + + // give DD1 some funds + executor.execute_and_apply( + mint_dd + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *dd1.address(), + XUS_THRESHOLD * 4, + vec![], + vec![], + )) + .sequence_number(0) + .sign(), + ); + // Give VASP some funds + executor.execute_and_apply( + mint_dd + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *parent_vasp.address(), + XUS_THRESHOLD * 2, + vec![], + vec![], + )) + .sequence_number(1) + .sign(), + ); + + // DD <-> DD over threshold without attestation succeeds + executor.execute_and_apply( + dd1.transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *dd2.address(), + XUS_THRESHOLD, + vec![0], + vec![], + )) + .sequence_number(1) + .sign(), + ); + // DD <-> DD over threshold with attestation succeeds + executor.execute_and_apply( + dd1.transaction() + .script(create_dual_attestation_payment( + *dd1.address(), + *dd2.address(), + XUS_THRESHOLD, + account_config::xus_tag(), + // pick an arbitrary ref_id + bcs::to_bytes(&9999u64).unwrap(), + &dd2_compliance_private_key, + )) + .sequence_number(2) + .sign(), + ); + + // DD -> VASP over threshold without attestation succeeds + executor.execute_and_apply( + dd1.transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *parent_vasp.address(), + XUS_THRESHOLD, + vec![0], + vec![], + )) + .sequence_number(3) + .sign(), + ); + // DD -> VASP over threshold with attestation succeeds + executor.execute_and_apply( + dd1.transaction() + .script(create_dual_attestation_payment( + *dd1.address(), + *parent_vasp.address(), + XUS_THRESHOLD, + account_config::xus_tag(), + // pick an arbitrary ref_id + bcs::to_bytes(&9999u64).unwrap(), + &parent_vasp_compliance_private_key, + )) + .sequence_number(4) + .sign(), + ); + + // VASP -> DD over threshold without attestation succeeds + executor.execute_and_apply( + parent_vasp + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *dd1.address(), + XUS_THRESHOLD, + vec![0], + vec![], + )) + .sequence_number(1) + .sign(), + ); + // VASP -> DD over threshold with attestation succeeds + executor.execute_and_apply( + parent_vasp + .transaction() + .script(create_dual_attestation_payment( + *parent_vasp.address(), + *dd1.address(), + XUS_THRESHOLD, + account_config::xus_tag(), + // pick an arbitrary ref_id + bcs::to_bytes(&9999u64).unwrap(), + &dd1_compliance_private_key, + )) + .sequence_number(2) + .sign(), + ); + + // VASP -> DD over threshold with opt-in, but bad attestation fails + let output = executor.execute_transaction( + parent_vasp + .transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *dd1.address(), + XUS_THRESHOLD, + vec![0], + b"what a bad signature".to_vec(), + )) + .sequence_number(3) + .sign(), + ); + assert_aborted_with(output, BAD_METADATA_SIGNATURE_ERROR_CODE) + } + } +} + +#[test] +fn publish_rotate_shared_ed25519_public_key() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + let mut publisher = { + let data = executor.create_raw_account_data(1_000_000, 0); + executor.add_account_data(&data); + data.into_account() + }; + // generate the key to initialize the SharedEd25519PublicKey resource + let mut keygen = KeyGen::from_seed([9u8; 32]); + let (private_key1, public_key1) = keygen.generate_keypair(); + executor.execute_and_apply( + publisher + .transaction() + .script(encode_publish_shared_ed25519_public_key_script( + public_key1.to_bytes().to_vec(), + )) + .sequence_number(0) + .sign(), + ); + // must rotate the key locally or sending subsequent txes will fail + publisher.rotate_key(private_key1, public_key1); + + // send another transaction rotating to a new key + let (private_key2, public_key2) = keygen.generate_keypair(); + executor.execute_and_apply( + publisher + .transaction() + .script(encode_rotate_shared_ed25519_public_key_script( + public_key2.to_bytes().to_vec(), + )) + .sequence_number(1) + .sign(), + ); + // must rotate the key in account data or sending subsequent txes will fail + publisher.rotate_key(private_key2, public_key2.clone()); + + // test that sending still works + executor.execute_and_apply( + publisher + .transaction() + .script(encode_rotate_shared_ed25519_public_key_script( + public_key2.to_bytes().to_vec(), + )) + .sequence_number(2) + .sign(), + ); + } + } +} + +#[test] +fn recovery_address() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + let blessed = test_env.tc_account; + + let parent = executor.create_raw_account(); + let mut child = executor.create_raw_account(); + let other_vasp = executor.create_raw_account(); + + let mut keygen = KeyGen::from_seed([9u8; 32]); + let (_vasp_compliance_private_key, _) = keygen.generate_keypair(); + + // create a parent VASP + let add_all_currencies = false; + executor.execute_and_apply( + blessed + .transaction() + .script(encode_create_parent_vasp_account_script( + account_config::xus_tag(), + 0, + *parent.address(), + parent.auth_key_prefix(), + vec![], + add_all_currencies, + )) + .sequence_number(test_env.tc_sequence_number) + .sign(), + ); + + // create a child VASP with a zero balance + executor.execute_and_apply( + parent + .transaction() + .script(encode_create_child_vasp_account_script( + account_config::xus_tag(), + *child.address(), + child.auth_key_prefix(), + add_all_currencies, + 0, + )) + .sequence_number(0) + .sign(), + ); + + // publish a recovery address under the parent + executor.execute_and_apply( + parent + .transaction() + .script(encode_create_recovery_address_script()) + .sequence_number(1) + .sign(), + ); + + // delegate authentication key of the child + executor.execute_and_apply( + child + .transaction() + .script(encode_add_recovery_rotation_capability_script( + *parent.address(), + )) + .sequence_number(0) + .sign(), + ); + + // rotate authentication key from the parent + let (privkey1, pubkey1) = keygen.generate_keypair(); + let new_authentication_key1 = AuthenticationKey::ed25519(&pubkey1).to_vec(); + executor.execute_and_apply( + parent + .transaction() + .script( + encode_rotate_authentication_key_with_recovery_address_script( + *parent.address(), + *child.address(), + new_authentication_key1, + ), + ) + .sequence_number(2) + .sign(), + ); + + // rotate authentication key from the child + let (_, pubkey2) = keygen.generate_keypair(); + let new_authentication_key2 = AuthenticationKey::ed25519(&pubkey2).to_vec(); + child.rotate_key(privkey1, pubkey1); + executor.execute_and_apply( + child + .transaction() + .script( + encode_rotate_authentication_key_with_recovery_address_script( + *parent.address(), + *child.address(), + new_authentication_key2, + ), + ) + .sequence_number(1) + .sign(), + ); + + // create another VASP unrelated to parent/child + let add_all_currencies = false; + executor.execute_and_apply( + blessed + .transaction() + .script(encode_create_parent_vasp_account_script( + account_config::xus_tag(), + 0, + *other_vasp.address(), + other_vasp.auth_key_prefix(), + vec![], + add_all_currencies, + )) + .sequence_number(test_env.tc_sequence_number.checked_add(1).unwrap()) + .sign(), + ); + + // try to delegate other_vasp's rotation cap to child--should abort + let output = executor.execute_transaction( + other_vasp + .transaction() + .script(encode_add_recovery_rotation_capability_script( + *parent.address(), + )) + .sequence_number(0) + .sign(), + ); + assert_aborted_with(output, 775); + + // try to rotate child's key from other_vasp--should abort + let (_, pubkey3) = keygen.generate_keypair(); + let new_authentication_key3 = AuthenticationKey::ed25519(&pubkey3).to_vec(); + let output = executor.execute_transaction( + other_vasp + .transaction() + .script( + encode_rotate_authentication_key_with_recovery_address_script( + *parent.address(), + *child.address(), + new_authentication_key3, + ), + ) + .sequence_number(0) + .sign(), + ); + assert_aborted_with(output, 519); + } + } +} + +#[test] +fn add_child_currencies() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + + let vasp_a = executor.create_raw_account(); + let vasp_a_child1 = executor.create_raw_account(); + let vasp_b = executor.create_raw_account(); + let vasp_b_child1 = executor.create_raw_account(); + let vasp_b_child2 = executor.create_raw_account(); + let blessed = Account::new_blessed_tc(); + let dr_account = Account::new_diem_root(); + let tc_sequence_number = 0; + + currencies::add_currency_to_system(&mut executor, "COIN", &dr_account, 0); + + executor.execute_and_apply( + blessed + .transaction() + .script(encode_create_parent_vasp_account_script( + account_config::xus_tag(), + 0, + *vasp_a.address(), + vasp_a.auth_key_prefix(), + vec![], + false, + )) + .sequence_number(tc_sequence_number) + .sign(), + ); + + // Adding a child with the same currency is no issue + executor.execute_and_apply( + vasp_a + .transaction() + .script(encode_create_child_vasp_account_script( + account_config::xus_tag(), + *vasp_a_child1.address(), + vasp_a_child1.auth_key_prefix(), + false, + 0, + )) + .sequence_number(0) + .sign(), + ); + + executor.execute_and_apply( + vasp_a + .transaction() + .script(encode_add_currency_to_account_script( + account_config::type_tag_for_currency_code(account::currency_code("COIN")), + )) + .sequence_number(1) + .sign(), + ); + + /////////////////////////////////////////////////////////////////////////// + // Now make a parent with all currencies, and make sure the children are fine + /////////////////////////////////////////////////////////////////////////// + + executor.execute_and_apply( + blessed + .transaction() + .script(encode_create_parent_vasp_account_script( + account_config::xus_tag(), + 0, + *vasp_b.address(), + vasp_b.auth_key_prefix(), + vec![], + true, + )) + .sequence_number(tc_sequence_number.checked_add(1).unwrap()) + .sign(), + ); + + // Adding a child with the same currency and all other currencies isn't an issue + executor.execute_and_apply( + vasp_b + .transaction() + .script(encode_create_child_vasp_account_script( + account_config::xus_tag(), + *vasp_b_child1.address(), + vasp_b_child1.auth_key_prefix(), + true, + 0, + )) + .sequence_number(0) + .sign(), + ); + // Adding a child with a different currency than the parent VASP is OK + executor.execute_and_apply( + vasp_b + .transaction() + .script(encode_create_child_vasp_account_script( + account_config::type_tag_for_currency_code(account::currency_code("COIN")), + *vasp_b_child2.address(), + vasp_b_child2.auth_key_prefix(), + false, + 0, + )) + .sequence_number(1) + .sign(), + ); +} diff --git a/vm/e2e-testsuite/src/tests/transaction_fees.rs b/vm/e2e-testsuite/src/tests/transaction_fees.rs new file mode 100644 index 0000000000..5be3c27abd --- /dev/null +++ b/vm/e2e-testsuite/src/tests/transaction_fees.rs @@ -0,0 +1,112 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use starcoin_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, Uniform}; +use diem_framework_releases::legacy::transaction_scripts::LegacyStdlibScript; +use diem_transaction_builder::stdlib::*; +use diem_types::{ + account_config::{self, BurnEvent, XUS_NAME}, + transaction::{authenticator::AuthenticationKey, Script, TransactionArgument}, + vm_status::KeptVMStatus, +}; +use move_core_types::{ + identifier::Identifier, + language_storage::{StructTag, TypeTag}, +}; +use starcoin_language_e2e_tests::{ + test_with_different_versions, versioning::CURRENT_RELEASE_VERSIONS, +}; +use std::convert::TryFrom; + +#[test] +fn burn_txn_fees() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + let sender = executor.create_raw_account(); + let dd = test_env.dd_account; + let blessed = test_env.tc_account; + + executor.execute_and_apply( + blessed + .transaction() + .script(encode_create_parent_vasp_account_script( + account_config::xus_tag(), + 0, + *sender.address(), + sender.auth_key_prefix(), + vec![], + false, + )) + .sequence_number(test_env.tc_sequence_number) + .sign(), + ); + + executor.execute_and_apply( + dd.transaction() + .script(encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *sender.address(), + 10_000_000, + vec![], + vec![], + )) + .sequence_number(test_env.dd_sequence_number) + .sign(), + ); + + let gas_used = { + let privkey = Ed25519PrivateKey::generate_for_testing(); + let pubkey = privkey.public_key(); + let new_key_hash = AuthenticationKey::ed25519(&pubkey).to_vec(); + let args = vec![TransactionArgument::U8Vector(new_key_hash)]; + let status = executor.execute_and_apply( + sender + .transaction() + .script(Script::new( + LegacyStdlibScript::RotateAuthenticationKey + .compiled_bytes() + .into_vec(), + vec![], + args, + )) + .sequence_number(0) + .gas_unit_price(1) + .gas_currency_code(XUS_NAME) + .sign(), + ); + assert_eq!(status.status().status(), Ok(KeptVMStatus::Executed)); + status.gas_used() + }; + + let xus_ty = TypeTag::Struct(StructTag { + address: account_config::CORE_CODE_ADDRESS, + module: Identifier::new("XUS").unwrap(), + name: Identifier::new("XUS").unwrap(), + type_params: vec![], + }); + + let output = executor.execute_and_apply( + blessed + .transaction() + .script(encode_burn_txn_fees_script(xus_ty)) + .sequence_number(test_env.tc_sequence_number.checked_add(1).unwrap()) + .sign(), + ); + + let burn_events: Vec<_> = output + .events() + .iter() + .filter_map(|event| BurnEvent::try_from(event).ok()) + .collect(); + + assert_eq!(burn_events.len(), 1); + assert!(burn_events + .iter() + .any(|event| event.currency_code().as_str() == "XUS")); + burn_events + .iter() + .for_each(|event| assert_eq!(event.amount(), gas_used)); + } + } +} diff --git a/vm/e2e-testsuite/src/tests/transaction_fuzzer.rs b/vm/e2e-testsuite/src/tests/transaction_fuzzer.rs new file mode 100644 index 0000000000..6ae35e3641 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/transaction_fuzzer.rs @@ -0,0 +1,93 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use diem_framework_releases::legacy::transaction_scripts::LegacyStdlibScript; +use diem_transaction_builder::stdlib::{encode_create_parent_vasp_account_script, ScriptCall}; +use diem_types::account_config; +use proptest::{collection::vec, prelude::*}; +use starcoin_language_e2e_tests::{ + account::{self, Account}, + executor::FakeExecutor, +}; +use std::convert::TryFrom; + +proptest! { + #![proptest_config(ProptestConfig::with_cases(10))] + #[test] + fn fuzz_scripts_genesis_state( + txns in vec(any::(), 0..10), + ) { + let executor = FakeExecutor::from_genesis_file(); + let accounts = vec![ + (Account::new_diem_root(), 0), + (Account::new_blessed_tc(), 0), + ]; + let num_accounts = accounts.len(); + + for (i, txn) in txns.into_iter().enumerate() { + let script = txn.encode(); + let (account, account_sequence_number) = &accounts[i % num_accounts]; + let output = executor.execute_transaction( + account.transaction() + .script(script.clone()) + .sequence_number(*account_sequence_number) + .sign()); + prop_assert!(!output.status().is_discarded()); + } + } + + #[test] + #[ignore] + fn fuzz_scripts( + txns in vec(any::(), 0..100), + ) { + let mut executor = FakeExecutor::from_genesis_file(); + let mut accounts = vec![]; + let diem_root = Account::new_diem_root(); + let coins = vec![account::xus_currency_code()]; + // Create a number of accounts + for i in 0..10 { + let account = executor.create_raw_account(); + executor.execute_and_apply( + diem_root + .transaction() + .script(encode_create_parent_vasp_account_script( + account_config::type_tag_for_currency_code(coins[i % coins.len()].clone()), + 0, + *account.address(), + account.auth_key_prefix(), + vec![], + i % 2 == 0, + )) + .sequence_number(i as u64) + .sign(), + ); + accounts.push((account, 0)); + } + // Don't include the DR account since txns from that can bork the system + accounts.push((Account::new_genesis_account(account_config::testnet_dd_account_address()), 0)); + accounts.push((Account::new_blessed_tc(), 0)); + let num_accounts = accounts.len(); + + for (i, txn) in txns.into_iter().enumerate() { + let script = txn.encode(); + let (account, account_sequence_number) = accounts.get_mut(i % num_accounts).unwrap(); + let script_is_rotate = LegacyStdlibScript::try_from(script.code()).map(|script| + script == LegacyStdlibScript::RotateAuthenticationKey || + script == LegacyStdlibScript::RotateAuthenticationKeyWithNonce || + script == LegacyStdlibScript::RotateAuthenticationKeyWithRecoveryAddress + ).unwrap_or(false); + let output = executor.execute_transaction( + account.transaction() + .script(script.clone()) + .sequence_number(*account_sequence_number) + .sign()); + prop_assert!(!output.status().is_discarded()); + // Don't apply key rotation transactions since that will bork future txns + if !script_is_rotate { + executor.apply_write_set(output.write_set()); + *account_sequence_number += 1; + } + } + } +} diff --git a/vm/e2e-testsuite/src/tests/validator_set_management.rs b/vm/e2e-testsuite/src/tests/validator_set_management.rs new file mode 100644 index 0000000000..0904908c6d --- /dev/null +++ b/vm/e2e-testsuite/src/tests/validator_set_management.rs @@ -0,0 +1,434 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use diem_types::{ + on_chain_config::{new_epoch_event_key, VMPublishingOption}, + transaction::{TransactionOutput, TransactionStatus, WriteSetPayload}, + vm_status::KeptVMStatus, +}; +use starcoin_language_e2e_tests::{ + account::Account, current_function_name, executor::FakeExecutor, test_with_different_versions, + versioning::CURRENT_RELEASE_VERSIONS, +}; +use starcoin_transaction_builder::stdlib::*; + +fn assert_aborted_with(output: TransactionOutput, error_code: u64) { + assert!(matches!( + output.status().status(), + Ok(KeptVMStatus::MoveAbort(_, code)) if code == error_code + )); +} + +fn try_add_validator( + executor: &mut FakeExecutor, + diem_root_account: &Account, + dr_seqno: u64, +) -> TransactionOutput { + let validator_account = executor.create_raw_account(); + let operator_account = executor.create_raw_account(); + + executor.execute_and_apply( + diem_root_account + .transaction() + .script(encode_create_validator_account_script( + 0, + *validator_account.address(), + validator_account.auth_key_prefix(), + b"validator_0".to_vec(), + )) + .sequence_number(dr_seqno) + .sign(), + ); + executor.execute_and_apply( + diem_root_account + .transaction() + .script(encode_create_validator_operator_account_script( + 0, + *operator_account.address(), + operator_account.auth_key_prefix(), + b"operator_0".to_vec(), + )) + .sequence_number(dr_seqno.checked_add(1).unwrap()) + .sign(), + ); + // validator sets operator + executor.execute_and_apply( + validator_account + .transaction() + .script(encode_set_validator_operator_script( + b"operator_0".to_vec(), + *operator_account.address(), + )) + .sequence_number(0) + .sign(), + ); + executor.new_block(); + + executor.execute_and_apply( + operator_account + .transaction() + .script(encode_register_validator_config_script( + *validator_account.address(), + [ + 0xd7, 0x5a, 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b, 0xfe, 0xd3, 0xc9, + 0x64, 0x07, 0x3a, 0x0e, 0xe1, 0x72, 0xf3, 0xda, 0xa6, 0x23, 0x25, 0xaf, 0x02, + 0x1a, 0x68, 0xf7, 0x07, 0x51, 0x1a, + ] + .to_vec(), + vec![254; 32], + vec![253; 32], + )) + .sequence_number(0) + .sign(), + ); + + executor.execute_transaction( + diem_root_account + .transaction() + .script(encode_add_validator_and_reconfigure_script( + 2, + b"validator_0".to_vec(), + *validator_account.address(), + )) + .sequence_number(dr_seqno.checked_add(2).unwrap()) + .sign(), + ) +} + +#[test] +fn validator_add() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + let output = try_add_validator(&mut executor, &test_env.dr_account, test_env.dr_sequence_number); + executor.apply_write_set(output.write_set()); + + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + assert!(output + .events() + .iter() + .any(|e| e.key() == &new_epoch_event_key())); + } + } +} + +#[test] +fn validator_add_max_number() { + let mut executor = FakeExecutor::custom_genesis( + diem_framework_releases::current_module_blobs(), + Some(256), + VMPublishingOption::open(), + ); + + executor.set_golden_file(current_function_name!()); + + let output = try_add_validator(&mut executor, &Account::new_diem_root(), 0); + + assert_aborted_with(output, 1800); +} + +#[test] +fn validator_rotate_key_and_reconfigure() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let diem_root_account = test_env.dr_account; + let validator_account = executor.create_raw_account(); + let validator_operator = executor.create_raw_account(); + + executor.execute_and_apply( + diem_root_account + .transaction() + .script(encode_create_validator_account_script( + 0, + *validator_account.address(), + validator_account.auth_key_prefix(), + b"validator_0".to_vec(), + )) + .sequence_number(test_env.dr_sequence_number) + .sign(), + ); + + executor.execute_and_apply( + diem_root_account + .transaction() + .script(encode_create_validator_operator_account_script( + 0, + *validator_operator.address(), + validator_operator.auth_key_prefix(), + b"bobby".to_vec(), + )) + .sequence_number(test_env.dr_sequence_number.checked_add(1).unwrap()) + .sign(), + ); + // validator_0 sets operator + executor.execute_and_apply( + validator_account + .transaction() + .script(encode_set_validator_operator_script( + b"bobby".to_vec(), + *validator_operator.address(), + )) + .sequence_number(0) + .sign(), + ); + + executor.new_block(); + + let output = executor.execute_and_apply( + validator_operator + .transaction() + .script(encode_register_validator_config_script( + *validator_account.address(), + [ + 0xd7, 0x5a, 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b, 0xfe, 0xd3, 0xc9, + 0x64, 0x07, 0x3a, 0x0e, 0xe1, 0x72, 0xf3, 0xda, 0xa6, 0x23, 0x25, 0xaf, 0x02, + 0x1a, 0x68, 0xf7, 0x07, 0x51, 0x1a, + ] + .to_vec(), + vec![254; 32], + vec![253; 32], + )) + .sequence_number(0) + .sign(), + ); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + + let output = executor.execute_and_apply( + diem_root_account + .transaction() + .script(encode_add_validator_and_reconfigure_script( + 2, + b"validator_0".to_vec(), + *validator_account.address(), + )) + .sequence_number(test_env.dr_sequence_number.checked_add(2).unwrap()) + .sign(), + ); + + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + assert!(output + .events() + .iter() + .any(|e| e.key() == &new_epoch_event_key())); + + executor.new_block_with_timestamp(300000010); + + let output = executor.execute_and_apply( + validator_operator + .transaction() + .script(encode_set_validator_config_and_reconfigure_script( + *validator_account.address(), + [ + 0x3d, 0x40, 0x17, 0xc3, 0xe8, 0x43, 0x89, 0x5a, 0x92, 0xb7, 0x0a, 0xa7, 0x4d, + 0x1b, 0x7e, 0xbc, 0x9c, 0x98, 0x2c, 0xcf, 0x2e, 0xc4, 0x96, 0x8c, 0xc0, 0xcd, + 0x55, 0xf1, 0x2a, 0xf4, 0x66, 0x0c, + ] + .to_vec(), + vec![254; 32], + vec![253; 32], + )) + .sequence_number(1) + .sign(), + ); + + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + assert!(output + .events() + .iter() + .any(|e| e.key() == &new_epoch_event_key())); + } + } +} + +#[test] +fn validator_set_operator_set_key_reconfigure() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let diem_root_account = test_env.dr_account; + let validator_account = executor.create_raw_account(); + let operator_account_0 = executor.create_raw_account(); + let operator_account_1 = executor.create_raw_account(); + + // Create operator 0 + let output = executor.execute_and_apply( + diem_root_account + .transaction() + .script(encode_create_validator_operator_account_script( + 0, + *operator_account_0.address(), + operator_account_0.auth_key_prefix(), + b"operator_0".to_vec(), + )) + .sequence_number(test_env.dr_sequence_number) + .sign(), + ); + + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + + // Create operator 1 + let output = executor.execute_and_apply( + diem_root_account + .transaction() + .script(encode_create_validator_operator_account_script( + 0, + *operator_account_1.address(), + operator_account_1.auth_key_prefix(), + b"operator_1".to_vec(), + )) + .sequence_number(test_env.dr_sequence_number.checked_add(1).unwrap()) + .sign(), + ); + + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + + // Create validator 0 + let output = executor.execute_and_apply( + diem_root_account + .transaction() + .script(encode_create_validator_account_script( + 0, + *validator_account.address(), + validator_account.auth_key_prefix(), + b"validator_0".to_vec(), + )) + .sequence_number(test_env.dr_sequence_number.checked_add(2).unwrap()) + .sign(), + ); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + executor.new_block(); + + // DR sets operator 1 for validator 0 + let admin_script = encode_set_validator_operator_with_nonce_admin_script( + 0, + b"operator_1".to_vec(), + *operator_account_1.address(), + ); + let txn = diem_root_account + .transaction() + .write_set(WriteSetPayload::Script { + script: admin_script, + execute_as: *validator_account.address(), + }) + .sequence_number(test_env.dr_sequence_number.checked_add(3).unwrap()) + .sign(); + executor.new_block(); + let output = executor.execute_transaction(txn); + + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + + // Validator then sets operator 0 + let output = executor.execute_and_apply( + validator_account + .transaction() + .script(encode_set_validator_operator_script( + b"operator_0".to_vec(), + *operator_account_0.address(), + )) + .sequence_number(0) + .sign(), + ); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + + let output = executor.execute_and_apply( + operator_account_0 + .transaction() + .script(encode_register_validator_config_script( + *validator_account.address(), + [ + 0x3d, 0x40, 0x17, 0xc3, 0xe8, 0x43, 0x89, 0x5a, 0x92, 0xb7, 0x0a, 0xa7, 0x4d, + 0x1b, 0x7e, 0xbc, 0x9c, 0x98, 0x2c, 0xcf, 0x2e, 0xc4, 0x96, 0x8c, 0xc0, 0xcd, + 0x55, 0xf1, 0x2a, 0xf4, 0x66, 0x0c, + ] + .to_vec(), + vec![254; 32], + vec![253; 32], + )) + .sequence_number(0) + .sign(), + ); + + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + + let output = executor.execute_and_apply( + diem_root_account + .transaction() + .script(encode_add_validator_and_reconfigure_script( + 3, + b"validator_0".to_vec(), + *validator_account.address(), + )) + .sequence_number(test_env.dr_sequence_number.checked_add(3).unwrap()) + .sign(), + ); + + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + assert!(output + .events() + .iter() + .any(|e| e.key() == &new_epoch_event_key())); + + executor.new_block_with_timestamp(300000010); + + let output = executor.execute_and_apply( + operator_account_0 + .transaction() + .script(encode_set_validator_config_and_reconfigure_script( + *validator_account.address(), + [ + 0xd7, 0x5a, 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b, 0xfe, 0xd3, 0xc9, + 0x64, 0x07, 0x3a, 0x0e, 0xe1, 0x72, 0xf3, 0xda, 0xa6, 0x23, 0x25, 0xaf, 0x02, + 0x1a, 0x68, 0xf7, 0x07, 0x51, 0x1a, + ] + .to_vec(), + vec![254; 32], + vec![253; 32], + )) + .sequence_number(1) + .sign(), + ); + + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + + assert!(output + .events() + .iter() + .any(|e| e.key() == &new_epoch_event_key())); + } + } +} diff --git a/vm/e2e-testsuite/src/tests/vasps.rs b/vm/e2e-testsuite/src/tests/vasps.rs new file mode 100644 index 0000000000..ef4f775a37 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/vasps.rs @@ -0,0 +1,196 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +#![forbid(unsafe_code)] + +use starcoin_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, Uniform}; +use diem_transaction_builder::stdlib::*; +use diem_types::{ + account_config, + transaction::{authenticator::AuthenticationKey, TransactionStatus}, + vm_status::KeptVMStatus, +}; +use move_core_types::{ + value::{serialize_values, MoveValue}, + vm_status::VMStatus, +}; +use starcoin_language_e2e_tests::{ + test_with_different_versions, versioning::CURRENT_RELEASE_VERSIONS, +}; + +#[test] +fn valid_creator_already_vasp() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + let account = executor.create_raw_account(); + + let treasury_compliance = test_env.tc_account; + + executor.execute_and_apply( + treasury_compliance + .transaction() + .script(encode_create_parent_vasp_account_script( + account_config::xus_tag(), + 0, + *account.address(), + account.auth_key_prefix(), + vec![], + true, + )) + .sequence_number(test_env.tc_sequence_number) + .sign(), + ); + + let err = executor + .try_exec( + "VASP", + "publish_parent_vasp_credential", + vec![], + serialize_values(&vec![ + MoveValue::Signer(*account.address()), + MoveValue::Signer(*treasury_compliance.address()), + ]), + ) + .unwrap_err(); + if let VMStatus::MoveAbort(_, code) = err { + assert_eq!(code, 6); + } else { + panic!("expected MoveAbort") + } + } + } +} + +#[test] +fn max_child_accounts_for_vasp_recovery_address() { + let max_num_child_accounts = 256; + + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + + let account = executor.create_raw_account(); + + let treasury_compliance = test_env.tc_account; + + executor.execute_and_apply( + treasury_compliance + .transaction() + .script(encode_create_parent_vasp_account_script( + account_config::xus_tag(), + 0, + *account.address(), + account.auth_key_prefix(), + vec![], + true, + )) + .sequence_number(test_env.tc_sequence_number) + .sign(), + ); + + let mut accounts = Vec::new(); + + // Batch the transactions to reduce the runtime of the test (cuts ~100 seconds) + let mut block = Vec::new(); + // Create the maximum number of allowed child accounts + for i in 0..max_num_child_accounts + 1 { + let child = executor.create_raw_account(); + accounts.push(child.clone()); + block.push( + account + .transaction() + .script(encode_create_child_vasp_account_script( + account_config::xus_tag(), + *child.address(), + child.auth_key_prefix(), + false, + 0, + )) + .sequence_number(i) + .sign(), + ); + } + + let output = executor.execute_block(block).unwrap(); + for output in output { + executor.apply_write_set(output.write_set()) + } + + // Now setup the recovery addresses + let recovery_account = accounts.remove(0); + let one_account_too_many = accounts.remove(0); + executor.execute_and_apply( + recovery_account + .transaction() + .script(encode_create_recovery_address_script()) + .sequence_number(0) + .sign(), + ); + + // Batch the transactions to reduce the runtime of the test (cuts ~ another 100 seconds) + let block = accounts + .iter() + .map(|account| { + account + .transaction() + .script(encode_add_recovery_rotation_capability_script( + *recovery_account.address(), + )) + .sequence_number(0) + .sign() + }) + .collect(); + + let outputs = executor.execute_block(block).unwrap(); + + for output in outputs { + executor.apply_write_set(output.write_set()) + } + + // Make sure that we can't add any more + let output = executor.execute_transaction( + one_account_too_many + .transaction() + .script(encode_add_recovery_rotation_capability_script( + *recovery_account.address(), + )) + .sequence_number(0) + .sign(), + ); + + if let Ok(KeptVMStatus::MoveAbort(_, code)) = output.status().status() { + assert_eq!(code, 1544); + } else { + panic!("expected MoveAbort") + } + + // Batch again, cuts about ~100 seconds more as well + let block = accounts + .iter() + .map(|account| { + let privkey = Ed25519PrivateKey::generate_for_testing(); + let pubkey = privkey.public_key(); + let new_key_hash = AuthenticationKey::ed25519(&pubkey).to_vec(); + account + .transaction() + .script( + encode_rotate_authentication_key_with_recovery_address_script( + *recovery_account.address(), + *account.address(), + new_key_hash, + ), + ) + .sequence_number(1) + .sign() + }) + .collect(); + + let outputs = executor.execute_block(block).unwrap(); + + // Now make sure all the rotations were executed + for output in outputs { + assert!(*output.status() == TransactionStatus::Keep(KeptVMStatus::Executed)); + } + } + } +} diff --git a/vm/e2e-testsuite/src/tests/verify_txn.rs b/vm/e2e-testsuite/src/tests/verify_txn.rs new file mode 100644 index 0000000000..d4d4df9c40 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/verify_txn.rs @@ -0,0 +1,1686 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +// use starcoin_crypto::{ +// ed25519::{Ed25519PrivateKey, Ed25519PublicKey}, +// multi_ed25519::{MultiEd25519PrivateKey, MultiEd25519PublicKey}, +// PrivateKey, SigningKey, Uniform, +// }; +// use starcoin_framework_releases::legacy::transaction_scripts::LegacyStdlibScript; +// use starcoin_keygen::KeyGen; +// use starcoin_transaction_builder::{ +// stdlib as transaction_builder, stdlib::encode_peer_to_peer_with_metadata_script, +// }; +// use starcoin_types::{ +// account_address::AccountAddress, +// account_config, +// chain_id::ChainId, +// on_chain_config::VMPublishingOption, +// test_helpers::transaction_test_helpers, +// transaction::{ +// authenticator::{AccountAuthenticator, AuthenticationKey, MAX_NUM_OF_SIGS}, +// RawTransactionWithData, Script, SignedTransaction, TransactionArgument, TransactionPayload, +// TransactionStatus, WriteSetPayload, +// }, +// vm_status::{KeptVMStatus, StatusCode}, +// }; +// use move_binary_format::file_format::CompiledModule; +// use move_core_types::{ +// gas_schedule::{GasAlgebra, GasConstants, MAX_TRANSACTION_SIZE_IN_BYTES}, +// identifier::Identifier, +// language_storage::{StructTag, TypeTag}, +// value::{serialize_values, MoveValue}, +// }; +// use move_ir_compiler::Compiler; +// use starcoin_language_e2e_tests::{ +// account::Account, +// assert_prologue_disparity, assert_prologue_parity, +// common_transactions::{ +// multi_agent_mint_script, multi_agent_swap_script, raw_multi_agent_swap_txn, rotate_key_txn, +// }, +// compile::compile_module, +// current_function_name, +// executor::FakeExecutor, +// gas_costs, test_with_different_versions, transaction_status_eq, +// versioning::CURRENT_RELEASE_VERSIONS, +// }; + +use starcoin_language_e2e_tests::executor::FakeExecutor; +use starcoin_language_e2e_tests::test_with_different_versions; + +#[test] +fn verify_signature() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let sender = executor.create_raw_account_data(900_000, 10); + executor.add_account_data(&sender); + // Generate a new key pair to try and sign things with. + let private_key = Ed25519PrivateKey::generate_for_testing(); + let program = encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *sender.address(), + 100, + vec![], + vec![], + ); + let signed_txn = transaction_test_helpers::get_test_unchecked_txn( + *sender.address(), + 0, + &private_key, + sender.account().pubkey.clone(), + Some(program), + ); + + assert_prologue_parity!( + executor.verify_transaction(signed_txn.clone()).status(), + executor.execute_transaction(signed_txn).status(), + StatusCode::INVALID_SIGNATURE + ); + } + } +} + +#[test] +fn verify_multi_agent() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + let sender = executor.create_raw_account_data(1_000_010, 10); + let secondary_signer = executor.create_raw_account_data(100_100, 100); + + executor.add_account_data(&sender); + executor.add_account_data(&secondary_signer); + + let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( + *sender.address(), + vec![*secondary_signer.address()], + 10, + &sender.account().privkey, + sender.account().pubkey.clone(), + vec![&secondary_signer.account().privkey], + vec![secondary_signer.account().pubkey.clone()], + Some(multi_agent_swap_script(10, 10)), + ); + assert_eq!(executor.verify_transaction(signed_txn).status(), None); +} + +#[test] +fn verify_multi_agent_multiple_secondary_signers() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + let sender = executor.create_raw_account_data(1_000_010, 10); + let secondary_signer = executor.create_raw_account_data(100_100, 100); + let third_signer = executor.create_raw_account_data(100_100, 100); + + executor.add_account_data(&sender); + executor.add_account_data(&secondary_signer); + executor.add_account_data(&third_signer); + + let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( + *sender.address(), + vec![*secondary_signer.address(), *third_signer.address()], + 10, + &sender.account().privkey, + sender.account().pubkey.clone(), + vec![ + &secondary_signer.account().privkey, + &third_signer.account().privkey, + ], + vec![ + secondary_signer.account().pubkey.clone(), + third_signer.account().pubkey.clone(), + ], + Some(multi_agent_mint_script(100, 0)), + ); + assert_eq!(executor.verify_transaction(signed_txn).status(), None); +} + +#[test] +fn verify_multi_agent_invalid_sender_signature() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + + let sender = executor.create_raw_account_data(1_000_010, 10); + let secondary_signer = executor.create_raw_account_data(100_100, 100); + + executor.add_account_data(&sender); + executor.add_account_data(&secondary_signer); + + let private_key = Ed25519PrivateKey::generate_for_testing(); + + // Sign using the wrong key for the sender, and correct key for the secondary signer. + let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( + *sender.address(), + vec![*secondary_signer.address()], + 10, + &private_key, + sender.account().pubkey.clone(), + vec![&secondary_signer.account().privkey], + vec![secondary_signer.account().pubkey.clone()], + None, + ); + assert_prologue_parity!( + executor.verify_transaction(signed_txn.clone()).status(), + executor.execute_transaction(signed_txn).status(), + StatusCode::INVALID_SIGNATURE + ); +} + +#[test] +fn verify_multi_agent_invalid_secondary_signature() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + let sender = executor.create_raw_account_data(1_000_010, 10); + let secondary_signer = executor.create_raw_account_data(100_100, 100); + + executor.add_account_data(&sender); + executor.add_account_data(&secondary_signer); + + let private_key = Ed25519PrivateKey::generate_for_testing(); + + // Sign using the correct keys for the sender, but wrong keys for the secondary signer. + let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( + *sender.address(), + vec![*secondary_signer.address()], + 10, + &sender.account().privkey, + sender.account().pubkey.clone(), + vec![&private_key], + vec![secondary_signer.account().pubkey.clone()], + None, + ); + assert_prologue_parity!( + executor.verify_transaction(signed_txn.clone()).status(), + executor.execute_transaction(signed_txn).status(), + StatusCode::INVALID_SIGNATURE + ); +} + +#[test] +fn verify_multi_agent_num_sigs_exceeds() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + let mut sender_seq_num = 10; + let secondary_signer_seq_num = 100; + let sender = executor.create_raw_account_data(1_000_010, sender_seq_num); + let secondary_signer = executor.create_raw_account_data(100_100, secondary_signer_seq_num); + + executor.add_account_data(&sender); + executor.add_account_data(&secondary_signer); + + // create two multisigs with `MAX_NUM_OF_SIGS/MAX_NUM_OF_SIGS` policy. + let mut keygen = KeyGen::from_seed([9u8; 32]); + let threshold = MAX_NUM_OF_SIGS as u8; + + let (sender_privkeys, sender_pubkeys): (Vec, Vec) = + (0..threshold).map(|_| keygen.generate_keypair()).unzip(); + let sender_multi_ed_public_key = MultiEd25519PublicKey::new(sender_pubkeys, threshold).unwrap(); + let sender_new_auth_key = AuthenticationKey::multi_ed25519(&sender_multi_ed_public_key); + + let (secondary_signer_privkeys, secondary_signer_pubkeys) = + (0..threshold).map(|_| keygen.generate_keypair()).unzip(); + let secondary_signer_multi_ed_public_key = + MultiEd25519PublicKey::new(secondary_signer_pubkeys, threshold).unwrap(); + let secondary_signer_new_auth_key = + AuthenticationKey::multi_ed25519(&secondary_signer_multi_ed_public_key); + + // (1) rotate keys to multisigs + let sender_output = &executor.execute_transaction(rotate_key_txn( + sender.account(), + sender_new_auth_key.to_vec(), + sender_seq_num, + )); + assert_eq!( + sender_output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed), + ); + executor.apply_write_set(sender_output.write_set()); + sender_seq_num += 1; + + let secondary_signer_output = &executor.execute_transaction(rotate_key_txn( + secondary_signer.account(), + secondary_signer_new_auth_key.to_vec(), + secondary_signer_seq_num, + )); + assert_eq!( + secondary_signer_output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed), + ); + executor.apply_write_set(secondary_signer_output.write_set()); + + // (2) sign a txn with new multisig private keys + let txn = raw_multi_agent_swap_txn( + sender.account(), + secondary_signer.account(), + sender_seq_num, + 0, + 0, + ); + let raw_txn_with_data = + RawTransactionWithData::new_multi_agent(txn.clone(), vec![*secondary_signer.address()]); + let sender_sig = MultiEd25519PrivateKey::new(sender_privkeys, threshold) + .unwrap() + .sign(&raw_txn_with_data); + let secondary_signer_sig = MultiEd25519PrivateKey::new(secondary_signer_privkeys, threshold) + .unwrap() + .sign(&raw_txn_with_data); + let signed_txn = SignedTransaction::new_multi_agent( + txn, + AccountAuthenticator::multi_ed25519(sender_multi_ed_public_key, sender_sig), + vec![*secondary_signer.address()], + vec![AccountAuthenticator::multi_ed25519( + secondary_signer_multi_ed_public_key, + secondary_signer_sig, + )], + ); + + // Transaction will fail validation because the number of signatures exceeds the maximum number + // of signatures allowed. + assert_prologue_parity!( + executor.verify_transaction(signed_txn.clone()).status(), + executor.execute_transaction(signed_txn).status(), + StatusCode::INVALID_SIGNATURE + ); +} + +#[test] +fn verify_multi_agent_wrong_number_of_signer() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + let sender = executor.create_raw_account_data(1_000_010, 10); + let secondary_signer = executor.create_raw_account_data(100_100, 100); + let third_signer = executor.create_raw_account_data(100_100, 100); + + executor.add_account_data(&sender); + executor.add_account_data(&secondary_signer); + executor.add_account_data(&third_signer); + + // Number of secondary signers according is 2 but we only + // include the signature of one of the secondary signers. + let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( + *sender.address(), + vec![*secondary_signer.address(), *third_signer.address()], + 10, + &sender.account().privkey, + sender.account().pubkey.clone(), + vec![&secondary_signer.account().privkey], + vec![secondary_signer.account().pubkey.clone()], + Some(multi_agent_mint_script(10, 0)), + ); + assert_prologue_parity!( + executor.verify_transaction(signed_txn.clone()).status(), + executor.execute_transaction(signed_txn).status(), + StatusCode::SECONDARY_KEYS_ADDRESSES_COUNT_MISMATCH + ); +} + +#[test] +fn verify_multi_agent_duplicate_sender() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + let sender = executor.create_raw_account_data(1_000_010, 10); + let secondary_signer = executor.create_raw_account_data(100_100, 100); + + executor.add_account_data(&sender); + executor.add_account_data(&secondary_signer); + // Duplicates in signers: sender and secondary signer have the same address. + let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( + *sender.address(), + vec![*sender.address()], + 10, + &sender.account().privkey, + sender.account().pubkey.clone(), + vec![&sender.account().privkey], + vec![sender.account().pubkey.clone()], + Some(multi_agent_swap_script(10, 10)), + ); + assert_prologue_parity!( + executor.verify_transaction(signed_txn.clone()).status(), + executor.execute_transaction(signed_txn).status(), + StatusCode::SIGNERS_CONTAIN_DUPLICATES + ); +} + +#[test] +fn verify_multi_agent_duplicate_secondary_signer() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + let sender = executor.create_raw_account_data(1_000_010, 10); + let secondary_signer = executor.create_raw_account_data(100_100, 100); + let third_signer = executor.create_raw_account_data(100_100, 100); + + executor.add_account_data(&sender); + executor.add_account_data(&secondary_signer); + executor.add_account_data(&third_signer); + + // Duplicates in secondary signers. + let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( + *sender.address(), + vec![ + *secondary_signer.address(), + *third_signer.address(), + *secondary_signer.address(), + ], + 10, + &sender.account().privkey, + sender.account().pubkey.clone(), + vec![ + &secondary_signer.account().privkey, + &third_signer.account().privkey, + &secondary_signer.account().privkey, + ], + vec![ + secondary_signer.account().pubkey.clone(), + third_signer.account().pubkey.clone(), + secondary_signer.account().pubkey.clone(), + ], + None, + ); + assert_prologue_parity!( + executor.verify_transaction(signed_txn.clone()).status(), + executor.execute_transaction(signed_txn).status(), + StatusCode::SIGNERS_CONTAIN_DUPLICATES + ); +} + +#[test] +fn verify_multi_agent_nonexistent_secondary_signer() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + let sender = executor.create_raw_account_data(1_000_010, 10); + let secondary_signer = executor.create_raw_account_data(100_100, 100); + + executor.add_account_data(&sender); + + // Duplicates in signers: sender and secondary signer have the same address. + let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( + *sender.address(), + vec![*secondary_signer.address()], + 10, + &sender.account().privkey, + sender.account().pubkey.clone(), + vec![&secondary_signer.account().privkey], + vec![secondary_signer.account().pubkey.clone()], + Some(multi_agent_swap_script(10, 10)), + ); + assert_prologue_parity!( + executor.verify_transaction(signed_txn.clone()).status(), + executor.execute_transaction(signed_txn).status(), + StatusCode::SENDING_ACCOUNT_DOES_NOT_EXIST + ); +} + +#[test] +fn verify_reserved_sender() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let sender = executor.create_raw_account_data(900_000, 10); + executor.add_account_data(&sender); + // Generate a new key pair to try and sign things with. + let private_key = Ed25519PrivateKey::generate_for_testing(); + let program = encode_peer_to_peer_with_metadata_script( + account_config::xus_tag(), + *sender.address(), + 100, + vec![], + vec![], + ); + let signed_txn = transaction_test_helpers::get_test_signed_txn( + account_config::reserved_vm_address(), + 0, + &private_key, + private_key.public_key(), + Some(TransactionPayload::Script(program)), + ); + + assert_prologue_parity!( + executor.verify_transaction(signed_txn.clone()).status(), + executor.execute_transaction(signed_txn).status(), + StatusCode::SENDING_ACCOUNT_DOES_NOT_EXIST + ); + } + } +} + +#[test] +fn verify_simple_payment() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + // create and publish a sender with 1_000_000 coins and a receiver with 100_000 coins + let sender = executor.create_raw_account_data(900_000, 10); + let receiver = executor.create_raw_account_data(100_000, 10); + executor.add_account_data(&sender); + executor.add_account_data(&receiver); + + // define the arguments to the peer to peer transaction + let transfer_amount = 1_000; + let args: Vec = vec![ + TransactionArgument::Address(*receiver.address()), + TransactionArgument::U64(transfer_amount), + TransactionArgument::U8Vector(vec![]), + TransactionArgument::U8Vector(vec![]), + ]; + + let p2p_script = LegacyStdlibScript::PeerToPeerWithMetadata + .compiled_bytes() + .into_vec(); + + // Create a new transaction that has the exact right sequence number. + let txn = sender + .account() + .transaction() + .script(Script::new( + p2p_script.clone(), + vec![account_config::xus_tag()], + args.clone(), + )) + .sequence_number(10) + .sign(); + assert_eq!(executor.verify_transaction(txn).status(), None); + + // Create a new transaction that has the bad auth key. + let txn = receiver + .account() + .transaction() + .script(Script::new( + p2p_script.clone(), + vec![account_config::xus_tag()], + args.clone(), + )) + .sequence_number(10) + .max_gas_amount(100_000) + .gas_unit_price(1) + .raw() + .sign(&sender.account().privkey, sender.account().pubkey.clone()) + .unwrap() + .into_inner(); + + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::INVALID_AUTH_KEY + ); + + // Create a new transaction that has a old sequence number. + let txn = sender + .account() + .transaction() + .script(Script::new( + p2p_script.clone(), + vec![account_config::xus_tag()], + args.clone(), + )) + .sequence_number(1) + .sign(); + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::SEQUENCE_NUMBER_TOO_OLD + ); + + // Create a new transaction that has a too new sequence number. + let txn = sender + .account() + .transaction() + .script(Script::new( + p2p_script.clone(), + vec![account_config::xus_tag()], + args.clone(), + )) + .sequence_number(11) + .sign(); + assert_prologue_disparity!( + executor.verify_transaction(txn.clone()).status() => None, + executor.execute_transaction(txn).status() => + TransactionStatus::Discard(StatusCode::SEQUENCE_NUMBER_TOO_NEW) + ); + + // Create a new transaction that doesn't have enough balance to pay for gas. + let txn = sender + .account() + .transaction() + .script(Script::new( + p2p_script.clone(), + vec![account_config::xus_tag()], + args.clone(), + )) + .sequence_number(10) + .max_gas_amount(1_000_000) + .gas_unit_price(1) + .sign(); + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::INSUFFICIENT_BALANCE_FOR_TRANSACTION_FEE + ); + + // Create a new transaction from a bogus account that doesn't exist + let bogus_account = executor.create_raw_account_data(100_000, 10); + let txn = bogus_account + .account() + .transaction() + .script(Script::new( + p2p_script.clone(), + vec![account_config::xus_tag()], + args.clone(), + )) + .sequence_number(10) + .sign(); + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::SENDING_ACCOUNT_DOES_NOT_EXIST + ); + + // The next couple tests test transaction size, and bounds on gas price and the number of + // gas units that can be submitted with a transaction. + // + // We test these in the reverse order that they appear in verify_transaction, and build up + // the errors one-by-one to make sure that we are both catching all of them, and + // that we are doing so in the specified order. + let gas_constants = &GasConstants::default(); + + let txn = sender + .account() + .transaction() + .script(Script::new( + p2p_script.clone(), + vec![account_config::xus_tag()], + args.clone(), + )) + .sequence_number(10) + .gas_unit_price(gas_constants.max_price_per_gas_unit.get() + 1) + .max_gas_amount(1_000_000) + .sign(); + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::GAS_UNIT_PRICE_ABOVE_MAX_BOUND + ); + + // Test for a max_gas_amount that is insufficient to pay the minimum fee. + // Find the minimum transaction gas units and subtract 1. + let mut gas_limit = gas_constants + .to_external_units(gas_constants.min_transaction_gas_units) + .get(); + if gas_limit > 0 { + gas_limit -= 1; + } + // Calculate how many extra bytes of transaction arguments to add to ensure + // that the minimum transaction gas gets rounded up when scaling to the + // external gas units. (Ignore the size of the script itself for simplicity.) + let extra_txn_bytes = if gas_constants.gas_unit_scaling_factor + > gas_constants.min_transaction_gas_units.get() + { + gas_constants.large_transaction_cutoff.get() + + (gas_constants.gas_unit_scaling_factor / gas_constants.intrinsic_gas_per_byte.get()) + } else { + 0 + }; + let txn = sender + .account() + .transaction() + .script(Script::new( + p2p_script.clone(), + vec![account_config::xus_tag()], + vec![TransactionArgument::U8(42); extra_txn_bytes as usize], + )) + .sequence_number(10) + .max_gas_amount(gas_limit) + .gas_unit_price(gas_constants.max_price_per_gas_unit.get()) + .sign(); + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::MAX_GAS_UNITS_BELOW_MIN_TRANSACTION_GAS_UNITS + ); + + let txn = sender + .account() + .transaction() + .script(Script::new( + p2p_script.clone(), + vec![account_config::xus_tag()], + args, + )) + .sequence_number(10) + .max_gas_amount(gas_constants.maximum_number_of_gas_units.get() + 1) + .gas_unit_price(gas_constants.max_price_per_gas_unit.get()) + .sign(); + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::MAX_GAS_UNITS_EXCEEDS_MAX_GAS_UNITS_BOUND + ); + + let txn = sender + .account() + .transaction() + .script(Script::new( + p2p_script.clone(), + vec![account_config::xus_tag()], + vec![TransactionArgument::U8(42); MAX_TRANSACTION_SIZE_IN_BYTES as usize], + )) + .sequence_number(10) + .max_gas_amount(gas_constants.maximum_number_of_gas_units.get() + 1) + .gas_unit_price(gas_constants.max_price_per_gas_unit.get()) + .sign(); + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::EXCEEDED_MAX_TRANSACTION_SIZE + ); + + // Create a new transaction that swaps the two arguments. + let args: Vec = vec![ + TransactionArgument::U64(transfer_amount), + TransactionArgument::Address(*receiver.address()), + ]; + + let txn = sender + .account() + .transaction() + .script(Script::new( + p2p_script.clone(), + vec![account_config::xus_tag()], + args, + )) + .sequence_number(10) + .max_gas_amount(100_000) + .gas_unit_price(1) + .sign(); + assert_eq!( + executor.execute_transaction(txn).status(), + // StatusCode::TYPE_MISMATCH + &TransactionStatus::Keep(KeptVMStatus::MiscellaneousError) + ); + + // Create a new transaction that has no argument. + let txn = sender + .account() + .transaction() + .script(Script::new( + p2p_script, + vec![account_config::xus_tag()], + vec![], + )) + .sequence_number(10) + .max_gas_amount(100_000) + .gas_unit_price(1) + .sign(); + assert_eq!( + executor.execute_transaction(txn).status(), + // StatusCode::TYPE_MISMATCH + &TransactionStatus::Keep(KeptVMStatus::MiscellaneousError) + ); + } + } +} + +#[test] +pub fn test_allowlist() { + // create a FakeExecutor with a genesis from file + let mut executor = FakeExecutor::allowlist_genesis(); + executor.set_golden_file(current_function_name!()); + // create an empty transaction + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + // When CustomScripts is off, a garbage script should be rejected with Keep(UnknownScript) + let random_script = vec![]; + let txn = sender + .account() + .transaction() + .script(Script::new(random_script, vec![], vec![])) + .sequence_number(10) + .max_gas_amount(100_000) + .gas_unit_price(1) + .sign(); + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::UNKNOWN_SCRIPT + ); +} + +#[test] +pub fn test_arbitrary_script_execution() { + // create a FakeExecutor with a genesis from file + let mut executor = + FakeExecutor::from_genesis_with_options(VMPublishingOption::custom_scripts()); + executor.set_golden_file(current_function_name!()); + + // create an empty transaction + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + // If CustomScripts is on, result should be Keep(DeserializationError). If it's off, the + // result should be Keep(UnknownScript) + let random_script = vec![]; + let txn = sender + .account() + .transaction() + .script(Script::new(random_script, vec![], vec![])) + .sequence_number(10) + .max_gas_amount(100_000) + .gas_unit_price(1) + .sign(); + assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + let status = executor.execute_transaction(txn).status().clone(); + assert!(!status.is_discarded()); + assert_eq!( + status.status(), + // StatusCode::CODE_DESERIALIZATION_ERROR + Ok(KeptVMStatus::MiscellaneousError) + ); +} + +#[test] +pub fn test_publish_from_diem_root() { + // create a FakeExecutor with a genesis from file + let mut executor = + FakeExecutor::from_genesis_with_options(VMPublishingOption::custom_scripts()); + executor.set_golden_file(current_function_name!()); + + // create a transaction trying to publish a new module. + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + let module = format!( + " + module 0x{}.M {{ + public max(a: u64, b: u64): u64 {{ + label b0: + jump_if (copy(a) > copy(b)) b2; + label b1: + return copy(b); + label b2: + return copy(a); + }} + + public sum(a: u64, b: u64): u64 {{ + let c: u64; + label b0: + c = copy(a) + copy(b); + return copy(c); + }} + }} + ", + sender.address(), + ); + + let random_module = compile_module(&module).1; + let txn = sender + .account() + .transaction() + .module(random_module) + .sequence_number(10) + .max_gas_amount(100_000) + .gas_unit_price(1) + .sign(); + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::INVALID_MODULE_PUBLISHER + ); +} + +#[test] +fn verify_expiration_time() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let sender = executor.create_raw_account_data(900_000, 0); + executor.add_account_data(&sender); + let private_key = &sender.account().privkey; + let txn = transaction_test_helpers::get_test_signed_transaction( + *sender.address(), + 0, /* sequence_number */ + private_key, + private_key.public_key(), + None, /* script */ + 0, /* expiration_time */ + 0, /* gas_unit_price */ + account_config::XUS_NAME.to_owned(), + None, /* max_gas_amount */ + ); + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::TRANSACTION_EXPIRED + ); + + // 10 is picked to make sure that SEQUENCE_NUMBER_TOO_NEW will not override the + // TRANSACTION_EXPIRED error. + let txn = transaction_test_helpers::get_test_signed_transaction( + *sender.address(), + 10, /* sequence_number */ + private_key, + private_key.public_key(), + None, /* script */ + 0, /* expiration_time */ + 0, /* gas_unit_price */ + account_config::XUS_NAME.to_owned(), + None, /* max_gas_amount */ + ); + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::TRANSACTION_EXPIRED + ); + } + } +} + +#[test] +fn verify_chain_id() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let sender = executor.create_raw_account_data(900_000, 0); + executor.add_account_data(&sender); + let private_key = Ed25519PrivateKey::generate_for_testing(); + let txn = transaction_test_helpers::get_test_txn_with_chain_id( + *sender.address(), + 0, + &private_key, + private_key.public_key(), + // all tests use ChainId::test() for chain_id,so pick something different + ChainId::new(ChainId::test().id() + 1), + ); + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::BAD_CHAIN_ID + ); + } + } +} + +#[test] +fn verify_gas_currency_with_bad_identifier() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let sender = executor.create_raw_account_data(900_000, 0); + executor.add_account_data(&sender); + let private_key = &sender.account().privkey; + let txn = transaction_test_helpers::get_test_signed_transaction( + *sender.address(), + 0, /* sequence_number */ + private_key, + private_key.public_key(), + None, /* script */ + u64::MAX, /* expiration_time */ + 0, /* gas_unit_price */ + // The gas currency code must be composed of alphanumeric characters and the + // first character must be a letter. + "Bad_ID".to_string(), + None, /* max_gas_amount */ + ); + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::INVALID_GAS_SPECIFIER + ); + } + } +} + +#[test] +fn verify_gas_currency_code() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let sender = executor.create_raw_account_data(900_000, 0); + executor.add_account_data(&sender); + let private_key = &sender.account().privkey; + let txn = transaction_test_helpers::get_test_signed_transaction( + *sender.address(), + 0, /* sequence_number */ + private_key, + private_key.public_key(), + None, /* script */ + u64::MAX, /* expiration_time */ + 0, /* gas_unit_price */ + "INVALID".to_string(), + None, /* max_gas_amount */ + ); + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::CURRENCY_INFO_DOES_NOT_EXIST + ); + } + } +} + +#[test] +fn verify_max_sequence_number() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let sender = executor.create_raw_account_data(900_000, std::u64::MAX); + executor.add_account_data(&sender); + let private_key = &sender.account().privkey; + let txn = transaction_test_helpers::get_test_signed_transaction( + *sender.address(), + std::u64::MAX, /* sequence_number */ + private_key, + private_key.public_key(), + None, /* script */ + u64::MAX, /* expiration_time */ + 0, /* gas_unit_price */ + "XUS".to_string(), + None, /* max_gas_amount */ + ); + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn).status(), + StatusCode::SEQUENCE_NUMBER_TOO_BIG + ); + } + } +} + +#[test] +pub fn test_no_publishing_diem_root_sender() { + // create a FakeExecutor with a genesis from file + let mut executor = + FakeExecutor::from_genesis_with_options(VMPublishingOption::custom_scripts()); + executor.set_golden_file(current_function_name!()); + + // create a transaction trying to publish a new module. + let sender = Account::new_diem_root(); + + let module = String::from( + " + module 0x1.M { + public max(a: u64, b: u64): u64 { + label b0: + jump_if (copy(a) > copy(b)) b2; + label b1: + return copy(b); + label b2: + return copy(a); + } + + public sum(a: u64, b: u64): u64 { + let c: u64; + label b0: + c = copy(a) + copy(b); + return copy(c); + } + } + ", + ); + + let random_module = compile_module(&module).1; + let txn = sender + .transaction() + .module(random_module) + .sequence_number(0) + .max_gas_amount(100_000) + .sign(); + assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!( + executor.execute_transaction(txn).status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); +} + +#[test] +pub fn test_open_publishing_invalid_address() { + // create a FakeExecutor with a genesis from file + let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + executor.set_golden_file(current_function_name!()); + + // create a transaction trying to publish a new module. + let sender = executor.create_raw_account_data(1_000_000, 10); + let receiver = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + executor.add_account_data(&receiver); + + let module = format!( + " + module 0x{}.M {{ + public max(a: u64, b: u64): u64 {{ + label b0: + jump_if (copy(a) > copy(b)) b2; + label b1: + return copy(b); + label b2: + return copy(a); + }} + + public sum(a: u64, b: u64): u64 {{ + let c: u64; + label b0: + c = copy(a) + copy(b); + return copy(c); + }} + }} + ", + receiver.address(), + ); + + let random_module = compile_module(&module).1; + let txn = sender + .account() + .transaction() + .module(random_module) + .sequence_number(10) + .max_gas_amount(100_000) + .gas_unit_price(1) + .sign(); + + // TODO: This is not verified for now. + // verify and fail because the addresses don't match + // let vm_status = executor.verify_transaction(txn.clone()).status().unwrap(); + + // assert!(vm_status.is(StatusType::Verification)); + // assert!(vm_status.major_status == StatusCode::MODULE_ADDRESS_DOES_NOT_MATCH_SENDER); + + // execute and fail for the same reason + let output = executor.execute_transaction(txn); + if let TransactionStatus::Keep(status) = output.status() { + // assert!(status.status_code() == StatusCode::MODULE_ADDRESS_DOES_NOT_MATCH_SENDER) + assert!(status == &KeptVMStatus::MiscellaneousError); + } else { + panic!("Unexpected execution status: {:?}", output) + }; +} + +#[test] +pub fn test_open_publishing() { + // create a FakeExecutor with a genesis from file + let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + executor.set_golden_file(current_function_name!()); + + // create a transaction trying to publish a new module. + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + let program = format!( + " + module 0x{}.M {{ + public max(a: u64, b: u64): u64 {{ + label b0: + jump_if (copy(a) > copy(b)) b2; + label b1: + return copy(b); + label b2: + return copy(a); + }} + + public sum(a: u64, b: u64): u64 {{ + let c: u64; + label b0: + c = copy(a) + copy(b); + return copy(c); + }} + }} + ", + sender.address(), + ); + + let random_module = compile_module(&program).1; + let txn = sender + .account() + .transaction() + .module(random_module) + .sequence_number(10) + .max_gas_amount(100_000) + .gas_unit_price(1) + .sign(); + assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!( + executor.execute_transaction(txn).status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); +} + +fn bad_module() -> (CompiledModule, Vec) { + let bad_module_code = " + module 0x1.Test { + struct R1 { b: bool } + struct S1 has copy, drop { r1: Self.R1 } + + public new_S1(): Self.S1 { + let s: Self.S1; + let r: Self.R1; + label b0: + r = R1 { b: true }; + s = S1 { r1: move(r) }; + return move(s); + } + } + "; + let compiler = Compiler { deps: vec![] }; + let module = compiler + .into_compiled_module(bad_module_code) + .expect("Failed to compile"); + let mut bytes = vec![]; + module.serialize(&mut bytes).unwrap(); + (module, bytes) +} + +fn good_module_uses_bad( + address: AccountAddress, + bad_dep: CompiledModule, +) -> (CompiledModule, Vec) { + let good_module_code = format!( + " + module 0x{}.Test2 {{ + import 0x1.Test; + struct S {{ b: bool }} + + foo(): Test.S1 {{ + label b0: + return Test.new_S1(); + }} + public bar() {{ + label b0: + return; + }} + }} + ", + address, + ); + + let compiler = Compiler { + deps: diem_framework_releases::current_modules() + .iter() + .chain(std::iter::once(&bad_dep)) + .collect(), + }; + let module = compiler + .into_compiled_module(good_module_code.as_str()) + .expect("Failed to compile"); + let mut bytes = vec![]; + module.serialize(&mut bytes).unwrap(); + (module, bytes) +} + +#[test] +fn test_script_dependency_fails_verification() { + let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + executor.set_golden_file(current_function_name!()); + + // Get a module that fails verification into the store. + let (module, bytes) = bad_module(); + executor.add_module(&module.self_id(), bytes); + + // Create a module that tries to use that module. + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + let code = " + import 0x1.Test; + + main() { + let x: Test.S1; + label b0: + x = Test.new_S1(); + return; + } + "; + + let compiler = Compiler { + deps: vec![&module], + }; + let script = compiler.into_script_blob(code).expect("Failed to compile"); + let txn = sender + .account() + .transaction() + .script(Script::new(script, vec![], vec![])) + .sequence_number(10) + .max_gas_amount(100_000) + .gas_unit_price(1) + .sign(); + // As of now, we verify module/script dependencies. This will result in an + // invariant violation as we try to load `Test` + assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + match executor.execute_transaction(txn).status() { + TransactionStatus::Discard(status) => { + assert_eq!(status, &StatusCode::UNEXPECTED_VERIFIER_ERROR); + } + _ => panic!("Kept transaction with an invariant violation!"), + } +} + +#[test] +fn test_module_dependency_fails_verification() { + let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + executor.set_golden_file(current_function_name!()); + + // Get a module that fails verification into the store. + let (bad_module, bad_module_bytes) = bad_module(); + executor.add_module(&bad_module.self_id(), bad_module_bytes); + + // Create a transaction that tries to use that module. + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + let good_module = { + let (_, serialized_module) = good_module_uses_bad(*sender.address(), bad_module); + diem_types::transaction::Module::new(serialized_module) + }; + + let txn = sender + .account() + .transaction() + .module(good_module) + .sequence_number(10) + .max_gas_amount(100_000) + .gas_unit_price(1) + .sign(); + // As of now, we verify module/script dependencies. This will result in an + // invariant violation as we try to load `Test` + assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + match executor.execute_transaction(txn).status() { + TransactionStatus::Discard(status) => { + assert_eq!(status, &StatusCode::UNEXPECTED_VERIFIER_ERROR); + } + _ => panic!("Kept transaction with an invariant violation!"), + } +} + +#[test] +fn test_type_tag_dependency_fails_verification() { + let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + executor.set_golden_file(current_function_name!()); + + // Get a module that fails verification into the store. + let (module, bytes) = bad_module(); + executor.add_module(&module.self_id(), bytes); + + // Create a transaction that tries to use that module. + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + let code = " + main() { + label b0: + return; + } + "; + + let compiler = Compiler { + deps: vec![&module], + }; + let script = compiler.into_script_blob(code).expect("Failed to compile"); + let txn = sender + .account() + .transaction() + .script(Script::new( + script, + vec![TypeTag::Struct(StructTag { + address: account_config::CORE_CODE_ADDRESS, + module: Identifier::new("Test").unwrap(), + name: Identifier::new("S1").unwrap(), + type_params: vec![], + })], + vec![], + )) + .sequence_number(10) + .max_gas_amount(100_000) + .gas_unit_price(1) + .sign(); + // As of now, we verify module/script dependencies. This will result in an + // invariant violation as we try to load `Test` + assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + match executor.execute_transaction(txn).status() { + TransactionStatus::Discard(status) => { + assert_eq!(status, &StatusCode::UNEXPECTED_VERIFIER_ERROR); + } + _ => panic!("Kept transaction with an invariant violation!"), + } +} + +#[test] +fn test_script_transitive_dependency_fails_verification() { + let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + executor.set_golden_file(current_function_name!()); + + // Get a module that fails verification into the store. + let (bad_module, bad_module_bytes) = bad_module(); + executor.add_module(&bad_module.self_id(), bad_module_bytes); + + // Create a module that tries to use that module. + let (good_module, good_module_bytes) = + good_module_uses_bad(account_config::CORE_CODE_ADDRESS, bad_module); + executor.add_module(&good_module.self_id(), good_module_bytes); + + // Create a transaction that tries to use that module. + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + let code = " + import 0x1.Test2; + + main() { + label b0: + Test2.bar(); + return; + } + "; + + let compiler = Compiler { + deps: vec![&good_module], + }; + let script = compiler.into_script_blob(code).expect("Failed to compile"); + let txn = sender + .account() + .transaction() + .script(Script::new(script, vec![], vec![])) + .sequence_number(10) + .max_gas_amount(100_000) + .gas_unit_price(1) + .sign(); + // As of now, we verify module/script dependencies. This will result in an + // invariant violation as we try to load `Test` + assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + match executor.execute_transaction(txn).status() { + TransactionStatus::Discard(status) => { + assert_eq!(status, &StatusCode::UNEXPECTED_VERIFIER_ERROR); + } + _ => panic!("Kept transaction with an invariant violation!"), + } +} + +#[test] +fn test_module_transitive_dependency_fails_verification() { + let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + executor.set_golden_file(current_function_name!()); + + // Get a module that fails verification into the store. + let (bad_module, bad_module_bytes) = bad_module(); + executor.add_module(&bad_module.self_id(), bad_module_bytes); + + // Create a module that tries to use that module. + let (good_module, good_module_bytes) = + good_module_uses_bad(account_config::CORE_CODE_ADDRESS, bad_module); + executor.add_module(&good_module.self_id(), good_module_bytes); + + // Create a transaction that tries to use that module. + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + let module_code = format!( + " + module 0x{}.Test3 {{ + import 0x1.Test2; + public bar() {{ + label b0: + Test2.bar(); + return; + }} + }} + ", + sender.address() + ); + let module = { + let compiler = Compiler { + deps: vec![&good_module], + }; + diem_types::transaction::Module::new( + compiler + .into_module_blob(module_code.as_str()) + .expect("Module compilation failed"), + ) + }; + + let txn = sender + .account() + .transaction() + .module(module) + .sequence_number(10) + .max_gas_amount(100_000) + .gas_unit_price(1) + .sign(); + // As of now, we verify module/script dependencies. This will result in an + // invariant violation as we try to load `Test` + assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + match executor.execute_transaction(txn).status() { + TransactionStatus::Discard(status) => { + assert_eq!(status, &StatusCode::UNEXPECTED_VERIFIER_ERROR); + } + _ => panic!("Kept transaction with an invariant violation!"), + } +} + +#[test] +fn test_type_tag_transitive_dependency_fails_verification() { + let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + executor.set_golden_file(current_function_name!()); + + // Get a module that fails verification into the store. + let (bad_module, bad_module_bytes) = bad_module(); + executor.add_module(&bad_module.self_id(), bad_module_bytes); + + // Create a module that tries to use that module. + let (good_module, good_module_bytes) = + good_module_uses_bad(account_config::CORE_CODE_ADDRESS, bad_module); + executor.add_module(&good_module.self_id(), good_module_bytes); + + // Create a transaction that tries to use that module. + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); + + let code = " + main() { + label b0: + return; + } + "; + + let compiler = Compiler { + deps: vec![&good_module], + }; + let script = compiler.into_script_blob(code).expect("Failed to compile"); + let txn = sender + .account() + .transaction() + .script(Script::new( + script, + vec![TypeTag::Struct(StructTag { + address: account_config::CORE_CODE_ADDRESS, + module: Identifier::new("Test2").unwrap(), + name: Identifier::new("S").unwrap(), + type_params: vec![], + })], + vec![], + )) + .sequence_number(10) + .max_gas_amount(100_000) + .gas_unit_price(1) + .sign(); + // As of now, we verify module/script dependencies. This will result in an + // invariant violation as we try to load `Test` + assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + match executor.execute_transaction(txn).status() { + TransactionStatus::Discard(status) => { + assert_eq!(status, &StatusCode::UNEXPECTED_VERIFIER_ERROR); + } + _ => panic!("Kept transaction with an invariant violation!"), + } +} + +#[test] +fn charge_gas_invalid_args() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let sender = executor.create_raw_account_data(1_000_000, 0); + executor.add_account_data(&sender); + + // get a SignedTransaction + let txn = sender + .account() + .transaction() + .script(Script::new( + LegacyStdlibScript::PeerToPeerWithMetadata + .compiled_bytes() + .into_vec(), + vec![account_config::xus_tag()], + // Don't pass any arguments + vec![], + )) + .sequence_number(0) + .max_gas_amount(gas_costs::TXN_RESERVED) + .sign(); + + let output = executor.execute_transaction(txn); + assert!(!output.status().is_discarded()); + assert!(output.gas_used() > 0); + } + } +} + +#[test] +pub fn publish_and_register_new_currency() { + // Test creating and registering a new currency and verify that it can + // only be used to pay transaction fees after it is initialized for that + // purpose. + + // create a FakeExecutor with a genesis from file + let mut executor = FakeExecutor::allowlist_genesis(); + executor.set_golden_file(current_function_name!()); + + // create a transaction trying to publish a new module. + let sender = Account::new_diem_root(); + let tc_account = Account::new_blessed_tc(); + + let module = r#" + module 0x1.COIN { + import 0x1.FixedPoint32; + import 0x1.Diem; + struct COIN has store { x: bool } + public initialize(dr_account: &signer, tc_account: &signer) { + label b0: + Diem.register_SCS_currency( + move(dr_account), + move(tc_account), + FixedPoint32.create_from_rational(1,2), + 100000, + 100, + h"434f494e", + ); + return; + } + } + "#; + + let (compiled_module, module) = compile_module(module); + let txn = sender + .transaction() + .module(module) + .sequence_number(0) + .sign(); + assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!( + executor.execute_and_apply(txn).status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + let coin_tag = account_config::type_tag_for_currency_code(Identifier::new("COIN").unwrap()); + + { + let program = { + let code = r#" + import 0x1.COIN; + main(lr_account: signer, tc_account: signer) { + label b0: + COIN.initialize(&lr_account, &tc_account); + return; + } + "#; + let compiler = Compiler { + deps: vec![&compiled_module], + }; + compiler.into_script_blob(code).expect("Failed to compile") + }; + let txn = sender + .transaction() + .write_set(WriteSetPayload::Script { + script: Script::new(program, vec![], vec![]), + execute_as: *tc_account.address(), + }) + .sequence_number(1) + .sign(); + executor.new_block(); + executor.execute_and_apply(txn); + } + + let dd = Account::new_from_seed(&mut KeyGen::from_seed([0; 32])); + + let txn = tc_account + .transaction() + .script(transaction_builder::encode_create_designated_dealer_script( + coin_tag.clone(), + 0, + *dd.address(), + dd.auth_key_prefix(), + b"".to_vec(), + true, + )) + .sequence_number(0) + .sign(); + + executor.execute_and_apply(txn); + + executor.exec( + "DesignatedDealer", + "add_currency", + vec![coin_tag.clone()], + serialize_values(&vec![ + MoveValue::Signer(*dd.address()), + MoveValue::Signer(*tc_account.address()), + ]), + ); + + let txn = tc_account + .transaction() + .script(transaction_builder::encode_tiered_mint_script( + coin_tag.clone(), + 0, + *dd.address(), + 50000, + 1, + )) + .sequence_number(1) + .sign(); + + executor.execute_and_apply(txn); + + let txn = dd + .transaction() + .script( + transaction_builder::encode_peer_to_peer_with_metadata_script( + coin_tag.clone(), + *dd.address(), + 1, + b"".to_vec(), + b"".to_vec(), + ), + ) + .gas_unit_price(1) + .max_gas_amount(800) + .gas_currency_code("COIN") + .sequence_number(0) + .sign(); + + let balance = executor.read_balance_resource(&dd, Identifier::new("COIN").unwrap()); + assert!(balance.unwrap().coin() > 800); + + assert_prologue_parity!( + executor.verify_transaction(txn.clone()).status(), + executor.execute_transaction(txn.clone()).status(), + StatusCode::BAD_TRANSACTION_FEE_CURRENCY + ); + + executor.exec( + "TransactionFee", + "add_txn_fee_currency", + vec![coin_tag], + serialize_values(&vec![MoveValue::Signer(*tc_account.address())]), + ); + + assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!( + executor.execute_transaction(txn).status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); +} diff --git a/vm/e2e-testsuite/src/tests/write_set.rs b/vm/e2e-testsuite/src/tests/write_set.rs new file mode 100644 index 0000000000..cfb65e7352 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/write_set.rs @@ -0,0 +1,359 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use starcoin_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, Uniform}; +use diem_types::{ + access_path::AccessPath, + account_config::{xus_tag, CORE_CODE_ADDRESS}, + chain_id::{ChainId, NamedChain}, + contract_event::ContractEvent, + on_chain_config::new_epoch_event_key, + transaction::{ + authenticator::AuthenticationKey, ChangeSet, TransactionStatus, WriteSetPayload, + }, + vm_status::{KeptVMStatus, StatusCode}, + write_set::{WriteOp, WriteSet, WriteSetMut}, +}; +use move_core_types::{ + identifier::Identifier, + language_storage::{ResourceKey, StructTag}, +}; +use starcoin_language_e2e_tests::{ + account, assert_prologue_parity, common_transactions::rotate_key_txn, + test_with_different_versions, transaction_status_eq, versioning::CURRENT_RELEASE_VERSIONS, +}; + +#[test] +fn invalid_write_set_signer() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let genesis_account = test_env.dr_account; + executor.new_block(); + + // Create a WriteSet that adds an account on a new address. + let new_account_data = executor.create_raw_account_data(0, 10); + let write_set = new_account_data.to_writeset(); + + // Signing the txn with a key that does not match the sender should fail. + let writeset_txn = genesis_account + .transaction() + .write_set(WriteSetPayload::Direct(ChangeSet::new(write_set, vec![]))) + .sequence_number(test_env.dr_sequence_number) + .raw() + .sign( + &new_account_data.account().privkey, + new_account_data.account().pubkey.clone(), + ) + .unwrap() + .into_inner(); + + assert_prologue_parity!( + executor.verify_transaction(writeset_txn.clone()).status(), + executor.execute_transaction(writeset_txn).status(), + StatusCode::INVALID_AUTH_KEY + ); + } + } +} + +#[test] +fn verify_and_execute_writeset() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let genesis_account = test_env.dr_account; + executor.new_block(); + + // Create a WriteSet that adds an account on a new address. + let new_account_data = executor.create_raw_account_data(0, 10); + let write_set = new_account_data.to_writeset(); + + // (1) Test that a correct WriteSet is executed as expected. + let writeset_txn = genesis_account + .transaction() + .write_set(WriteSetPayload::Direct(ChangeSet::new( + write_set.clone(), + vec![], + ))) + .sequence_number(test_env.dr_sequence_number) + .sign(); + let output = executor.execute_transaction(writeset_txn.clone()); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + assert!(executor + .verify_transaction(writeset_txn.clone()) + .status() + .is_none()); + + executor.apply_write_set(output.write_set()); + + let updated_diem_root_account = executor + .read_account_resource(&genesis_account) + .expect("sender must exist"); + let updated_sender = executor + .read_account_resource(new_account_data.account()) + .expect("sender must exist"); + let updated_sender_balance = executor + .read_balance_resource(new_account_data.account(), account::xus_currency_code()) + .expect("sender balance must exist"); + + assert_eq!(test_env.dr_sequence_number.checked_add(1).unwrap(), updated_diem_root_account.sequence_number()); + assert_eq!(0, updated_sender_balance.coin()); + assert_eq!(10, updated_sender.sequence_number()); + + // (2) Cannot reapply the same writeset. + assert_prologue_parity!( + executor.verify_transaction(writeset_txn.clone()).status(), + executor.execute_transaction(writeset_txn).status(), + StatusCode::SEQUENCE_NUMBER_TOO_OLD + ); + + // (3) Cannot apply the writeset with future sequence number. + let writeset_txn = genesis_account + .transaction() + .write_set(WriteSetPayload::Direct(ChangeSet::new(write_set, vec![]))) + .sequence_number(test_env.dr_sequence_number.checked_add(10).unwrap()) + .sign(); + let output = executor.execute_transaction(writeset_txn.clone()); + assert_eq!( + output.status(), + &TransactionStatus::Discard(StatusCode::SEQUENCE_NUMBER_TOO_NEW) + ); + // "Too new" sequence numbers are accepted during validation. + assert!(executor.verify_transaction(writeset_txn).status().is_none()); + } + } +} + +#[test] +fn bad_writesets() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let genesis_account = test_env.dr_account; + executor.new_block(); + + // Create a WriteSet that adds an account on a new address + let new_account_data = executor.create_raw_account_data(1000, 10); + let write_set = new_account_data.to_writeset(); + + // (1) A WriteSet signed by an arbitrary account, not Diem root, should be rejected. + let writeset_txn = new_account_data + .account() + .transaction() + .write_set(WriteSetPayload::Direct(ChangeSet::new( + write_set.clone(), + vec![], + ))) + .sequence_number(0) + .sign(); + assert_prologue_parity!( + executor.verify_transaction(writeset_txn.clone()).status(), + executor.execute_transaction(writeset_txn).status(), + StatusCode::REJECTED_WRITE_SET + ); + + // (2) A WriteSet containing a reconfiguration event should be dropped. + let event = ContractEvent::new(new_epoch_event_key(), 0, xus_tag(), vec![]); + let writeset_txn = genesis_account + .transaction() + .write_set(WriteSetPayload::Direct(ChangeSet::new( + write_set, + vec![event], + ))) + .sequence_number(test_env.dr_sequence_number) + .sign(); + assert_eq!( + executor.execute_transaction(writeset_txn).status(), + &TransactionStatus::Discard(StatusCode::INVALID_WRITE_SET) + ); + + // (3) A WriteSet attempting to change DiemWriteSetManager should be dropped. + let key = ResourceKey::new( + *genesis_account.address(), + StructTag { + address: CORE_CODE_ADDRESS, + module: Identifier::new("DiemAccount").unwrap(), + name: Identifier::new("DiemWriteSetManager").unwrap(), + type_params: vec![], + }, + ); + let path = AccessPath::resource_access_path(key); + + let write_set = WriteSetMut::new(vec![(path, WriteOp::Value(vec![]))]) + .freeze() + .unwrap(); + let writeset_txn = genesis_account + .transaction() + .write_set(WriteSetPayload::Direct(ChangeSet::new(write_set, vec![]))) + .sequence_number(test_env.dr_sequence_number) + .sign(); + let output = executor.execute_transaction(writeset_txn); + assert_eq!( + output.status(), + &TransactionStatus::Discard(StatusCode::INVALID_WRITE_SET) + ); + + // (4) A WriteSet attempting to change Diem root AccountResource should be dropped. + let key = ResourceKey::new( + *genesis_account.address(), + StructTag { + address: CORE_CODE_ADDRESS, + module: Identifier::new("DiemAccount").unwrap(), + name: Identifier::new("DiemAccount").unwrap(), + type_params: vec![], + }, + ); + let path = AccessPath::resource_access_path(key); + + let write_set = WriteSetMut::new(vec![(path, WriteOp::Value(vec![]))]) + .freeze() + .unwrap(); + let writeset_txn = genesis_account + .transaction() + .write_set(WriteSetPayload::Direct(ChangeSet::new(write_set, vec![]))) + .sequence_number(test_env.dr_sequence_number) + .sign(); + let output = executor.execute_transaction(writeset_txn); + assert_eq!( + output.status(), + &TransactionStatus::Discard(StatusCode::INVALID_WRITE_SET) + ); + + // (5) A WriteSet with a bad ChainId should be rejected. + let writeset_txn = genesis_account + .transaction() + .write_set(WriteSetPayload::Direct(ChangeSet::new( + WriteSet::default(), + vec![], + ))) + .sequence_number(test_env.dr_sequence_number) + .chain_id(ChainId::new(NamedChain::DEVNET.id())) + .sign(); + assert_prologue_parity!( + executor.verify_transaction(writeset_txn.clone()).status(), + executor.execute_transaction(writeset_txn).status(), + StatusCode::BAD_CHAIN_ID + ); + + // (6) A WriteSet that has expired should be rejected. + let writeset_txn = genesis_account + .transaction() + .write_set(WriteSetPayload::Direct(ChangeSet::new( + WriteSet::default(), + vec![], + ))) + .sequence_number(test_env.dr_sequence_number) + .ttl(0) + .sign(); + assert_prologue_parity!( + executor.verify_transaction(writeset_txn.clone()).status(), + executor.execute_transaction(writeset_txn).status(), + StatusCode::TRANSACTION_EXPIRED + ); + + // (7) The gas currency specified in the transaction must be valid + // (even though WriteSet transactions are not charged for gas). + let writeset_txn = genesis_account + .transaction() + .write_set(WriteSetPayload::Direct(ChangeSet::new( + WriteSet::default(), + vec![], + ))) + .sequence_number(test_env.dr_sequence_number) + .gas_currency_code("Bad_ID") + .sign(); + assert_prologue_parity!( + executor.verify_transaction(writeset_txn.clone()).status(), + executor.execute_transaction(writeset_txn).status(), + StatusCode::INVALID_GAS_SPECIFIER + ); + + // (8) The gas currency code must also correspond to a registered currency + // (even though WriteSet transactions are not charged for gas). + let writeset_txn = genesis_account + .transaction() + .write_set(WriteSetPayload::Direct(ChangeSet::new( + WriteSet::default(), + vec![], + ))) + .sequence_number(test_env.dr_sequence_number) + .gas_currency_code("INVALID") + .sign(); + assert_prologue_parity!( + executor.verify_transaction(writeset_txn.clone()).status(), + executor.execute_transaction(writeset_txn).status(), + StatusCode::CURRENCY_INFO_DOES_NOT_EXIST + ); + } + } +} + +#[test] +fn transfer_and_execute_writeset() { + test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = test_env.executor; + let genesis_account = test_env.dr_account; + let blessed_account = test_env.tc_account; + executor.new_block(); + + let receiver = executor.create_raw_account_data(100_000, 10); + executor.add_account_data(&receiver); + + // (1) Association mint some coin + let privkey = Ed25519PrivateKey::generate_for_testing(); + let pubkey = privkey.public_key(); + let new_key_hash = AuthenticationKey::ed25519(&pubkey).to_vec(); + + executor.execute_and_apply(rotate_key_txn(&blessed_account, new_key_hash, test_env.tc_sequence_number)); + + // (2) Create a WriteSet that adds an account on a new address + let new_account_data = executor.create_raw_account_data(0, 10); + let write_set = new_account_data.to_writeset(); + + let writeset_txn = genesis_account + .transaction() + .write_set(WriteSetPayload::Direct(ChangeSet::new(write_set, vec![]))) + .sequence_number(test_env.dr_sequence_number) + .sign(); + + let output = executor.execute_transaction(writeset_txn.clone()); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + assert!(executor.verify_transaction(writeset_txn).status().is_none()); + + executor.apply_write_set(output.write_set()); + + let updated_diem_root_account = executor + .read_account_resource(&genesis_account) + .expect("sender must exist"); + let updated_sender = executor + .read_account_resource(new_account_data.account()) + .expect("sender must exist"); + let updated_sender_balance = executor + .read_balance_resource(new_account_data.account(), account::xus_currency_code()) + .expect("sender balance must exist"); + + assert_eq!(test_env.dr_sequence_number.checked_add(1).unwrap(), updated_diem_root_account.sequence_number()); + assert_eq!(0, updated_sender_balance.coin()); + assert_eq!(10, updated_sender.sequence_number()); + + // (3) Rotate the accounts key + let privkey = Ed25519PrivateKey::generate_for_testing(); + let pubkey = privkey.public_key(); + let new_key_hash = AuthenticationKey::ed25519(&pubkey).to_vec(); + let txn = rotate_key_txn(new_account_data.account(), new_key_hash, 10); + + // execute transaction + let output = executor.execute_transaction(txn); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + + executor.apply_write_set(output.write_set()); + } + } +} diff --git a/vm/e2e-testsuite/src/tests/writeset_builder.rs b/vm/e2e-testsuite/src/tests/writeset_builder.rs new file mode 100644 index 0000000000..2c88eb3b7b --- /dev/null +++ b/vm/e2e-testsuite/src/tests/writeset_builder.rs @@ -0,0 +1,101 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 +use diem_types::{ + access_path::AccessPath, + on_chain_config::DiemVersion, + transaction::{ChangeSet, Script, TransactionStatus, WriteSetPayload}, + vm_status::KeptVMStatus, + write_set::WriteOp, +}; +use diem_vm::DiemVM; +use diem_writeset_generator::build_changeset; +use move_ir_compiler::Compiler; +use starcoin_language_e2e_tests::{ + account::Account, compile::compile_module, current_function_name, executor::FakeExecutor, +}; + +#[test] +fn build_upgrade_writeset() { + let mut executor = FakeExecutor::from_genesis_file(); + executor.set_golden_file(current_function_name!()); + + // create a transaction trying to publish a new module. + let genesis_account = Account::new_diem_root(); + + let program = String::from( + " + module 0x1.M { + public magic(): u64 { label b0: return 42; } + } + ", + ); + + let module = compile_module(&program).0; + let module_bytes = { + let mut v = vec![]; + module.serialize(&mut v).unwrap(); + v + }; + let change_set = { + let (version_writes, events) = build_changeset(executor.get_state_view(), |session| { + session.set_diem_version(11); + }) + .into_inner(); + let mut writeset = version_writes.into_mut(); + writeset.push(( + AccessPath::code_access_path(module.self_id()), + WriteOp::Value(module_bytes), + )); + ChangeSet::new(writeset.freeze().unwrap(), events) + }; + + let writeset_txn = genesis_account + .transaction() + .write_set(WriteSetPayload::Direct(change_set)) + .sequence_number(0) + .sign(); + + let output = executor.execute_transaction(writeset_txn.clone()); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + assert!(executor.verify_transaction(writeset_txn).status().is_none()); + + executor.apply_write_set(output.write_set()); + + let new_vm = DiemVM::new(executor.get_state_view()); + assert_eq!( + new_vm.internals().diem_version().unwrap(), + DiemVersion { major: 11 } + ); + + let script_body = { + let code = r#" +import 0x1.M; + +main(lr_account: signer) { +label b0: + assert(M.magic() == 42, 100); + return; +} +"#; + + let compiler = Compiler { + deps: vec![&module], + }; + compiler.into_script_blob(code).expect("Failed to compile") + }; + + let txn = genesis_account + .transaction() + .script(Script::new(script_body, vec![], vec![])) + .sequence_number(1) + .sign(); + + let output = executor.execute_transaction(txn); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); +} diff --git a/vm/transaction-benchmarks/src/main.rs b/vm/transaction-benchmarks/src/main.rs index 39536f4a4d..a887b87924 100644 --- a/vm/transaction-benchmarks/src/main.rs +++ b/vm/transaction-benchmarks/src/main.rs @@ -50,16 +50,21 @@ fn main() { "Transaction numbers level array is empty!" ); - // if !concurrency_levels.is_empty() { - // run_par = true; - // } + if !concurrency_levels.is_empty() { + run_par = true; + } + + // let acts = [2]; + // let txns = [1]; + // let num_warmups = 2; + // let num_runs = 1; let bencher = TransactionBencher::new(any_with::((1_000, 1_000_000))); // let acts = [1000]; //let txns = [10000, 50000, 100000]; - let num_warmups = 2; - let num_runs = 10; + // let num_warmups = 2; + // let num_runs = 10; println!( "num cpus = {}, run_seq: {}, run_seq: {}", From 9ea8ee19c84d19a39b3c20dc1d389dc3f559c0b0 Mon Sep 17 00:00:00 2001 From: welbon Date: Wed, 8 Nov 2023 19:11:31 +0800 Subject: [PATCH 63/89] [e2e-testsuite] cherry pick from branch tps_benchmark_e2e_testsuite --- vm/e2e-tests/src/on_chain_configs.rs | 62 +- vm/e2e-tests/src/versioning.rs | 3 +- vm/e2e-testsuite/Cargo.toml | 4 +- vm/e2e-testsuite/src/tests/account_limits.rs | 732 ------------------ vm/e2e-testsuite/src/tests/admin_script.rs | 106 ++- vm/e2e-testsuite/src/tests/create_account.rs | 25 +- vm/e2e-testsuite/src/tests/crsn.rs | 298 ------- vm/e2e-testsuite/src/tests/data_store.rs | 26 +- .../src/tests/emergency_admin_script.rs | 20 +- .../src/tests/execution_strategies.rs | 40 +- vm/e2e-testsuite/src/tests/experimental.rs | 14 +- .../src/tests/failed_transaction_tests.rs | 13 +- vm/e2e-testsuite/src/tests/genesis.rs | 7 +- .../src/tests/genesis_initializations.rs | 48 +- vm/e2e-testsuite/src/tests/mint.rs | 11 +- vm/e2e-testsuite/src/tests/mod.rs | 4 +- .../src/tests/module_publishing.rs | 16 +- vm/e2e-testsuite/src/tests/multi_agent.rs | 14 - .../src/tests/on_chain_configs.rs | 2 +- .../src/tests/parallel_execution.rs | 21 +- vm/e2e-testsuite/src/tests/peer_to_peer.rs | 15 +- vm/e2e-testsuite/src/tests/rotate_key.rs | 10 +- .../src/tests/transaction_builder.rs | 21 +- .../src/tests/transaction_fees.rs | 2 +- .../src/tests/transaction_fuzzer.rs | 4 +- .../src/tests/validator_set_management.rs | 2 +- vm/e2e-testsuite/src/tests/vasps.rs | 2 +- vm/e2e-testsuite/src/tests/verify_txn.rs | 58 +- vm/e2e-testsuite/src/tests/write_set.rs | 2 +- .../src/tests/writeset_builder.rs | 4 +- vm/parallel-executor/src/scheduler.rs | 619 +++++++++++++++ vm/transaction-benchmarks/src/main.rs | 4 +- 32 files changed, 840 insertions(+), 1369 deletions(-) delete mode 100644 vm/e2e-testsuite/src/tests/account_limits.rs delete mode 100644 vm/e2e-testsuite/src/tests/crsn.rs create mode 100644 vm/parallel-executor/src/scheduler.rs diff --git a/vm/e2e-tests/src/on_chain_configs.rs b/vm/e2e-tests/src/on_chain_configs.rs index 1cba36b585..ffa2c053fa 100644 --- a/vm/e2e-tests/src/on_chain_configs.rs +++ b/vm/e2e-tests/src/on_chain_configs.rs @@ -1,22 +1,64 @@ // Copyright (c) Starcoin // SPDX-License-Identifier: Apache-2.0 +use crate::account::Account; use crate::executor::FakeExecutor; +use move_core_types::transaction_argument::{convert_txn_args, TransactionArgument}; +use move_ir_compiler::Compiler; +use starcoin_vm_runtime::starcoin_vm::StarcoinVM; +use starcoin_vm_types::genesis_config::StdlibVersion; use starcoin_vm_types::on_chain_config::Version; +use starcoin_vm_types::transaction::Script; +use stdlib::{stdlib_compiled_modules, StdLibOptions}; -pub fn set_starcoin_version(_executor: &mut FakeExecutor, _version: Version) { - // TODO(BobOng): e2e-test - // let account = - // Account::new_genesis_account(starcoin_vm_types::on_chain_config::config_address()); +pub fn set_starcoin_version(executor: &mut FakeExecutor, version: Version) { + let account = + Account::new_genesis_account(starcoin_vm_types::account_config::genesis_address()); // let txn = account // .transaction() + // .script( + // LegacyStdlibScript::UpdateDiemVersion + // .compiled_bytes() + // .into_vec(), + // vec![], + // vec![ + // TransactionArgument::U64(0), + // TransactionArgument::U64(version.major), + // ],) // .payload(starcoin_stdlib::encode_version_set_version(version.major)) // .sequence_number(0) // .sign(); - // executor.new_block(); - // executor.execute_and_apply(txn); - // - // //let new_vm = StarcoinVM::new(executor.get_state_view()); - // let new_vm = StarcoinVM::new(None); - // assert_eq!(new_vm.internals().version().unwrap(), version); + let script_body = { + let code = r#" +import 0x1.Config; +import 0x1.LanguageVersion; + +main(account: signer, language_version: u8) { + // initialize the language version config. + Config::publish_new_config(sender, LanguageVersion::new(language_version)); +} +"#; + + let modules = stdlib_compiled_modules(StdLibOptions::Compiled(StdlibVersion::Latest)); + let compiler = Compiler { + deps: modules.iter().collect(), + }; + compiler.into_script_blob(code).expect("Failed to compile") + }; + // let account = Account::new_starcoin_root(); + let txn = account + .transaction() + .script(Script::new( + script_body, + vec![], + convert_txn_args(&vec![TransactionArgument::U64(version.major)]), + )) + .sequence_number(0) + .sign(); + + executor.new_block(); + executor.execute_and_apply(txn); + + let new_vm = StarcoinVM::new(None); + assert_eq!(new_vm.get_version().unwrap(), version); } diff --git a/vm/e2e-tests/src/versioning.rs b/vm/e2e-tests/src/versioning.rs index 6ed6ca4763..2677e94029 100644 --- a/vm/e2e-tests/src/versioning.rs +++ b/vm/e2e-tests/src/versioning.rs @@ -3,14 +3,13 @@ #![forbid(unsafe_code)] -use starcoin_vm_types::on_chain_config::G_VERSION_CONFIG_IDENTIFIER; use crate::{account::Account, executor::FakeExecutor, utils}; /// The current version numbers that e2e tests should be run against. // pub const CURRENT_RELEASE_VERSIONS: std::ops::RangeInclusive = // STARCOIN_MAX_KNOWN_VERSION.major..=STARCOIN_MAX_KNOWN_VERSION.major; -pub const CURRENT_RELEASE_VERSIONS: std::ops::RangeInclusive = 1..=DIEM_MAX_KNOWN_VERSION.major; +pub const CURRENT_RELEASE_VERSIONS: std::ops::RangeInclusive = 1..=12; #[derive(Debug)] pub struct VersionedTestEnv { diff --git a/vm/e2e-testsuite/Cargo.toml b/vm/e2e-testsuite/Cargo.toml index a864d4f709..2ee7a8ce74 100644 --- a/vm/e2e-testsuite/Cargo.toml +++ b/vm/e2e-testsuite/Cargo.toml @@ -25,7 +25,7 @@ move-binary-format = { workspace = true } move-bytecode-verifier = { workspace = true } read-write-set = { workspace = true } -## Diem-Move dependencies +## Starcoin Move dependencies starcoin-language-e2e-tests = { workspace = true } starcoin-logger = { workspace = true } starcoin-transaction-builder = { workspace = true } @@ -33,6 +33,8 @@ starcoin-vm-runtime = { workspace = true } starcoin-vm-types = { workspace = true } starcoin-types = { workspace = true } starcoin-crypto = { workspace = true } + + #diem-keygen = { path = "../diem-keygen" } #starcoin-vm = { path = "../starcoin-vm" } #diem-framework-releases = { path = "../diem-framework/DPN/releases" } diff --git a/vm/e2e-testsuite/src/tests/account_limits.rs b/vm/e2e-testsuite/src/tests/account_limits.rs deleted file mode 100644 index a4bcddab35..0000000000 --- a/vm/e2e-testsuite/src/tests/account_limits.rs +++ /dev/null @@ -1,732 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// SPDX-License-Identifier: Apache-2.0 - -#![forbid(unsafe_code)] - -use move_ir_compiler::Compiler; -use starcoin_language_e2e_tests::{ - account::{self, Account}, - current_function_name, - executor::FakeExecutor, -}; -use starcoin_types::{ - account_address::AccountAddress, - account_config, - transaction::{Script, TransactionArgument, TransactionOutput, WriteSetPayload}, -}; -use starcoin_transaction_builder::stdlib::*; - -fn assert_aborted_with(output: TransactionOutput, error_code: u64) { - assert!(matches!( - output.status().status(), - Ok(KeptVMStatus::MoveAbort(_, code)) if code == error_code - )); -} - -fn encode_add_account_limits_admin_script(execute_as: AccountAddress) -> WriteSetPayload { - let add_account_limits_admin_script = { - let code = " - import 0x1.AccountLimits; - import 0x1.XUS; - import 0x1.Signer; - - main(dr_account: signer, vasp: signer) { - label b0: - AccountLimits.publish_unrestricted_limits_for_testing(&vasp); - AccountLimits.publish_window( - &dr_account, - &vasp, - Signer.address_of(&vasp) - ); - return; - } -"; - let compiler = Compiler { - deps: starcoin_framework_releases::current_modules().iter().collect(), - }; - compiler.into_script_blob(code).expect("Failed to compile") - }; - - WriteSetPayload::Script { - script: Script::new(add_account_limits_admin_script, vec![], vec![]), - execute_as, - } -} - -fn encode_update_account_limit_definition_script( - limit_addr: AccountAddress, - new_max_inflow: u64, - new_max_outflow: u64, - new_max_holding_balance: u64, - new_time_period: u64, -) -> Script { - let script_body = { - let code = " - import 0x1.AccountLimits; - import 0x1.XUS; - - main( - account: signer, - limit_addr: address, - new_max_inflow: u64, - new_max_outflow: u64, - new_max_holding_balance: u64, - new_time_period: u64 - ) { - label b0: - AccountLimits.update_limits_definition( - &account, - move(limit_addr), - move(new_max_inflow), - move(new_max_outflow), - move(new_max_holding_balance), - move(new_time_period), - ); - return; - } -"; - let compiler = Compiler { - deps: starcoin_framework_releases::current_modules().iter().collect(), - }; - compiler.into_script_blob(code).expect("Failed to compile") - }; - - Script::new( - script_body, - vec![], - vec![ - TransactionArgument::Address(limit_addr), - TransactionArgument::U64(new_max_inflow), - TransactionArgument::U64(new_max_outflow), - TransactionArgument::U64(new_max_holding_balance), - TransactionArgument::U64(new_time_period), - ], - ) -} - -fn encode_update_account_limit_window_info_script( - window_addr: AccountAddress, - aggregate_balance: u64, - new_limit_address: AccountAddress, -) -> Script { - let script_body = { - let code = " - import 0x1.AccountLimits; - import 0x1.XUS; - - main(account: signer, - window_addr: address, - aggregate_balance: u64, - new_limit_address: address - ) { - label b0: - AccountLimits.update_window_info( - &account, - move(window_addr), - move(aggregate_balance), - move(new_limit_address), - ); - return; - } -"; - let compiler = Compiler { - deps: diem_framework_releases::current_modules().iter().collect(), - }; - compiler.into_script_blob(code).expect("Failed to compile") - }; - - Script::new( - script_body, - vec![], - vec![ - TransactionArgument::Address(window_addr), - TransactionArgument::U64(aggregate_balance), - TransactionArgument::Address(new_limit_address), - ], - ) -} - -#[test] -fn account_limits() { - let mut executor = FakeExecutor::from_genesis_file(); - executor.set_golden_file(current_function_name!()); - let vasp_a = executor.create_raw_account(); - let vasp_b = executor.create_raw_account(); - let vasp_a_child = executor.create_raw_account(); - let vasp_b_child = executor.create_raw_account(); - let diem_root = Account::new_diem_root(); - let blessed = Account::new_blessed_tc(); - let dd = Account::new_testing_dd(); - let dr_sequence_number = 0; - let tc_sequence_number = 0; - let dd_sequence_number = 0; - - let mint_amount = 1_000_000; - let window_micros = 86400000000; - let ttl = window_micros; - - // Create vasp accounts - executor.execute_and_apply( - blessed - .transaction() - .script(encode_create_parent_vasp_account_script( - account_config::xus_tag(), - 0, - *vasp_a.address(), - vasp_a.auth_key_prefix(), - vec![], - true, - )) - .sequence_number(tc_sequence_number) - .ttl(ttl) - .sign(), - ); - executor.execute_and_apply( - blessed - .transaction() - .script(encode_create_parent_vasp_account_script( - account_config::xus_tag(), - 0, - *vasp_b.address(), - vasp_b.auth_key_prefix(), - vec![], - true, - )) - .sequence_number(tc_sequence_number.checked_add(1).unwrap()) - .ttl(ttl) - .sign(), - ); - - // Create child vasp accounts - executor.execute_and_apply( - vasp_a - .transaction() - .script(encode_create_child_vasp_account_script( - account_config::xus_tag(), - *vasp_a_child.address(), - vasp_a_child.auth_key_prefix(), - true, - 0, - )) - .sequence_number(0) - .ttl(ttl) - .sign(), - ); - executor.execute_and_apply( - vasp_b - .transaction() - .script(encode_create_child_vasp_account_script( - account_config::xus_tag(), - *vasp_b_child.address(), - vasp_b_child.auth_key_prefix(), - true, - 0, - )) - .sequence_number(0) - .ttl(ttl) - .sign(), - ); - - executor.execute_and_apply( - diem_root - .transaction() - .write_set(encode_add_account_limits_admin_script(*vasp_a.address())) - .sequence_number(dr_sequence_number) - .sign(), - ); - - executor.execute_and_apply( - diem_root - .transaction() - .write_set(encode_add_account_limits_admin_script(*vasp_b.address())) - .sequence_number(dr_sequence_number.checked_add(1).unwrap()) - .sign(), - ); - - // mint money to both vasp A & B - executor.execute_and_apply( - dd.transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_a.address(), - 2 * mint_amount, - vec![], - vec![], - )) - .sequence_number(dd_sequence_number) - .ttl(ttl) - .sign(), - ); - executor.execute_and_apply( - dd.transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_b.address(), - 2 * mint_amount, - vec![], - vec![], - )) - .sequence_number(dd_sequence_number.checked_add(1).unwrap()) - .ttl(ttl) - .sign(), - ); - - executor.execute_and_apply( - blessed - .transaction() - .script(encode_update_account_limit_window_info_script( - *vasp_a.address(), - 0, - *vasp_a.address(), - )) - .sequence_number(tc_sequence_number.checked_add(2).unwrap()) - .ttl(ttl) - .sign(), - ); - - /////////////////////////////////////////////////////////////////////////// - // Inflow tests - ///////////////////////////////////////////////////////////////////////////// - - // Set vasp A's inflow limit to half of what we just minted them - executor.execute_and_apply( - blessed - .transaction() - .script(encode_update_account_limit_definition_script( - *vasp_a.address(), - mint_amount, - 0, - 0, - 0, - )) - .sequence_number(tc_sequence_number.checked_add(3).unwrap()) - .ttl(ttl) - .sign(), - ); - - { - // Now try and pay in to vasp A; fails since inflow is exceeded - let output = executor.execute_transaction( - vasp_b - .transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_a.address(), - mint_amount + 1, - vec![], - vec![], - )) - .sequence_number(1) - .ttl(ttl) - .sign(), - ); - assert_aborted_with(output, 776); - } - - { - // Now try and pay in to child of vasp A; fails since inflow is exceeded - let output = executor.execute_transaction( - vasp_b - .transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_a_child.address(), - mint_amount + 1, - vec![], - vec![], - )) - .sequence_number(1) - .ttl(ttl) - .sign(), - ); - assert_aborted_with(output, 776); - } - - // Intra-vasp transfer isn't limited - executor.execute_and_apply( - vasp_a - .transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_a_child.address(), - mint_amount + 1, - vec![], - vec![], - )) - .sequence_number(1) - .ttl(ttl) - .sign(), - ); - - // Only inflow is limited; can send from vasp a still - executor.execute_and_apply( - vasp_a_child - .transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_b_child.address(), - mint_amount + 1, - vec![], - vec![], - )) - .sequence_number(0) - .ttl(ttl) - .sign(), - ); - - // The previous mints don't count in this window since it wasn't a vasp->vasp transfer - executor.execute_and_apply( - vasp_b_child - .transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_a_child.address(), - mint_amount, - vec![], - vec![], - )) - .sequence_number(0) - .ttl(ttl) - .sign(), - ); - - { - // DD deposit fails since vasp A is at inflow limit - let output = executor.execute_transaction( - dd.transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_a_child.address(), - 1, - vec![], - vec![], - )) - .sequence_number(dd_sequence_number.checked_add(2).unwrap()) - .ttl(ttl) - .sign(), - ); - assert_aborted_with(output, 776); - - // Reset the window - let prev_block_time = executor.get_block_time(); - executor.set_block_time(prev_block_time + window_micros); - executor.new_block(); - - // DD deposit now succeeds since window is reset - let output = executor.execute_transaction( - dd.transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_a_child.address(), - 1, - vec![], - vec![], - )) - .sequence_number(dd_sequence_number.checked_add(2).unwrap()) - .ttl(ttl) - .sign(), - ); - assert_eq!(output.status().status(), Ok(KeptVMStatus::Executed)); - } - - /////////////////////////////////////////////////////////////////////////// - // Outflow tests - ///////////////////////////////////////////////////////////////////////////// - - // Set vasp A's outflow to 1000 - executor.execute_and_apply( - blessed - .transaction() - .script(encode_update_account_limit_definition_script( - *vasp_a.address(), - std::u64::MAX, // unlimit inflow - 1000, // set outflow to 1000 - 0, - 0, - )) - .sequence_number(tc_sequence_number.checked_add(4).unwrap()) - .ttl(ttl) - .sign(), - ); - - // Intra-vasp transfer isn't limited - executor.execute_and_apply( - vasp_a - .transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_a_child.address(), - 1001, - vec![], - vec![], - )) - .sequence_number(2) - .ttl(ttl) - .sign(), - ); - - // Can send up to the limit inter-vasp: - executor.execute_and_apply( - vasp_a_child - .transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_b_child.address(), - 1000, - vec![], - vec![], - )) - .sequence_number(1) - .ttl(ttl) - .sign(), - ); - - { - // Inter-vasp transfer is limited - let output = executor.execute_transaction( - vasp_a - .transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_b.address(), - 1, - vec![], - vec![], - )) - .sequence_number(3) - .ttl(ttl) - .sign(), - ); - assert_aborted_with(output, 1544); - } - - { - // Inter-vasp transfer is limited; holds between children too - let output = executor.execute_transaction( - vasp_a_child - .transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_b_child.address(), - 1, - vec![], - vec![], - )) - .sequence_number(2) - .ttl(ttl) - .sign(), - ); - assert_aborted_with(output, 1544); - } - - { - // vasp->anything transfer is limited - let output = executor.execute_transaction( - vasp_a_child - .transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *dd.address(), - 1, - vec![], - vec![], - )) - .sequence_number(2) - .ttl(ttl) - .sign(), - ); - assert_aborted_with(output, 1544); - - // update block time - let prev_block_time = executor.get_block_time(); - executor.set_block_time(prev_block_time + window_micros); - executor.new_block(); - - let output = executor.execute_transaction( - vasp_a_child - .transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *dd.address(), - 1, - vec![], - vec![], - )) - .sequence_number(2) - .ttl(window_micros) - .ttl(ttl) - .sign(), - ); - assert_eq!(output.status().status(), Ok(KeptVMStatus::Executed),); - } - - /////////////////////////////////////////////////////////////////////////// - // Holding tests - ///////////////////////////////////////////////////////////////////////////// - - // Set vasp A's max holding to its current balance across all accounts - { - let a_parent_balance = executor - .read_balance_resource(&vasp_a, account::xus_currency_code()) - .unwrap() - .coin(); - let a_child_balance = executor - .read_balance_resource(&vasp_a_child, account::xus_currency_code()) - .unwrap() - .coin(); - let a_balance = a_parent_balance + a_child_balance; - executor.execute_and_apply( - blessed - .transaction() - .script(encode_update_account_limit_definition_script( - *vasp_a.address(), - 0, - std::u64::MAX, // unlimit outflow - a_balance, // set max holding to the current balance of A - 0, - )) - .sequence_number(tc_sequence_number.checked_add(5).unwrap()) - .ttl(ttl) - .sign(), - ); - // TC needs to set the current aggregate balance for vasp a's window - executor.execute_and_apply( - blessed - .transaction() - .script(encode_update_account_limit_window_info_script( - *vasp_a.address(), - a_balance, - *vasp_a.address(), - )) - .sequence_number(tc_sequence_number.checked_add(6).unwrap()) - .ttl(ttl) - .sign(), - ); - } - - // inter-vasp: fails since limit is set at A's current balance - { - let output = executor.execute_transaction( - vasp_b - .transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_a_child.address(), - 1, - vec![], - vec![], - )) - .sequence_number(1) - .ttl(ttl) - .sign(), - ); - assert_aborted_with(output, 776); - } - - // Fine since A can still send - executor.execute_and_apply( - vasp_a - .transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_b_child.address(), - 10, - vec![], - vec![], - )) - .sequence_number(3) - .ttl(ttl) - .sign(), - ); - - // inter-vasp: OK since A's total balance = limit - 10 - executor.execute_and_apply( - vasp_b - .transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_a_child.address(), - 10, - vec![], - vec![], - )) - .sequence_number(1) - .ttl(ttl) - .sign(), - ); - - { - // inter-vasp: should now fail again - let output = executor.execute_transaction( - vasp_b - .transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_a_child.address(), - 1, - vec![], - vec![], - )) - .sequence_number(2) - .ttl(ttl) - .sign(), - ); - assert_aborted_with(output, 776); - } - - // intra-vasp: OK since it isn't checked/contributes to the total balance - executor.execute_and_apply( - vasp_a_child - .transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_a.address(), - 1100, - vec![], - vec![], - )) - .sequence_number(2) - .ttl(ttl) - .sign(), - ); - - { - // DD deposit fails since vasp A is at holding limit - let output = executor.execute_transaction( - dd.transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_a_child.address(), - 1, - vec![], - vec![], - )) - .sequence_number(dd_sequence_number.checked_add(2).unwrap()) - .ttl(ttl) - .sign(), - ); - assert_aborted_with(output, 776); - - // Reset window - let prev_block_time = executor.get_block_time(); - executor.set_block_time(prev_block_time + window_micros); - executor.new_block(); - - // DD deposit fails since vasp A is at holding limit - // and because holdings are not reset from one window to the next. - let output = executor.execute_transaction( - dd.transaction() - .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), - *vasp_a_child.address(), - 1, - vec![], - vec![], - )) - .sequence_number(dd_sequence_number.checked_add(2).unwrap()) - .ttl(ttl) - .sign(), - ); - assert_aborted_with(output, 776); - } -} diff --git a/vm/e2e-testsuite/src/tests/admin_script.rs b/vm/e2e-testsuite/src/tests/admin_script.rs index 38066340b4..d49afd8e9a 100644 --- a/vm/e2e-testsuite/src/tests/admin_script.rs +++ b/vm/e2e-testsuite/src/tests/admin_script.rs @@ -1,18 +1,18 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use starcoin_language_e2e_tests::{ - account::Account, current_function_name, executor::FakeExecutor, -}; - -use starcoin_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, Uniform}; -use diem_types::{ - transaction::{authenticator::AuthenticationKey, Script, TransactionArgument}, - vm_status::StatusCode, -}; - -use diem_types::transaction::WriteSetPayload; +use move_core_types::transaction_argument::TransactionArgument; +use move_core_types::vm_status::StatusCode; use move_ir_compiler::Compiler; +use starcoin_crypto::ed25519::Ed25519PrivateKey; +use starcoin_crypto::{PrivateKey, Uniform}; +use starcoin_language_e2e_tests::account::Account; +use starcoin_language_e2e_tests::{current_function_name, executor::FakeExecutor}; +use starcoin_transaction_builder::{stdlib_compiled_modules, StdLibOptions}; +use starcoin_vm_types::genesis_config::StdlibVersion::Latest; +use starcoin_vm_types::on_chain_config; +use starcoin_vm_types::transaction::authenticator::AuthenticationKey; +use starcoin_vm_types::transaction::Script; #[test] fn admin_script_rotate_key_single_signer_no_epoch() { @@ -27,42 +27,38 @@ fn admin_script_rotate_key_single_signer_no_epoch() { let script_body = { let code = r#" -import 0x1.DiemAccount; +import StarcoinFramework.Account; -main(dr_account: signer, account: signer, auth_key_prefix: vector) { - let rotate_cap: DiemAccount.KeyRotationCapability; +main(account: signer, auth_key_prefix: vector) { + let rotate_cap: Account::KeyRotationCapability; label b0: - rotate_cap = DiemAccount.extract_key_rotation_capability(&account); - DiemAccount.rotate_authentication_key(&rotate_cap, move(auth_key_prefix)); - DiemAccount.restore_key_rotation_capability(move(rotate_cap)); + rotate_cap = Account.extract_key_rotation_capability(&account); + Account.rotate_authentication_key(&rotate_cap, move(auth_key_prefix)); + Account.restore_key_rotation_capability(move(rotate_cap)); return; } "#; let compiler = Compiler { - deps: diem_framework_releases::current_modules().iter().collect(), + deps: stdlib_compiled_modules(StdLibOptions::Compiled(Latest)) + .iter() + .collect(), }; compiler.into_script_blob(code).expect("Failed to compile") }; - let account = Account::new_diem_root(); + + let account = Account::new_starcoin_root(); let txn = account .transaction() - .write_set(WriteSetPayload::Script { - script: Script::new( - script_body, - vec![], - vec![TransactionArgument::U8Vector(new_key_hash.clone())], - ), - execute_as: *new_account.address(), - }) + .script(Script::new(script_body, vec![], vec![new_key_hash.clone()])) .sequence_number(0) .sign(); executor.new_block(); let output = executor.execute_and_apply(txn); // The transaction should not trigger a reconfiguration. - let new_epoch_event_key = diem_types::on_chain_config::new_epoch_event_key(); + let new_epoch_event_key = on_chain_config::new_epoch_event_key(); assert!(!output .events() .iter() @@ -88,44 +84,39 @@ fn admin_script_rotate_key_single_signer_new_epoch() { let script_body = { let code = r#" -import 0x1.DiemAccount; +import 0x1.Account; import 0x1.DiemConfig; main(dr_account: signer, account: signer, auth_key_prefix: vector) { - let rotate_cap: DiemAccount.KeyRotationCapability; + let rotate_cap: Account.KeyRotationCapability; label b0: - rotate_cap = DiemAccount.extract_key_rotation_capability(&account); - DiemAccount.rotate_authentication_key(&rotate_cap, move(auth_key_prefix)); - DiemAccount.restore_key_rotation_capability(move(rotate_cap)); + rotate_cap = Account.extract_key_rotation_capability(&account); + Account.rotate_authentication_key(&rotate_cap, move(auth_key_prefix)); + Account.restore_key_rotation_capability(move(rotate_cap)); - DiemConfig.reconfigure(&dr_account); + Config.reconfigure(&dr_account); return; } "#; let compiler = Compiler { - deps: diem_framework_releases::current_modules().iter().collect(), + deps: stdlib_compiled_modules(StdLibOptions::Compiled(Latest)) + .iter() + .collect(), }; compiler.into_script_blob(code).expect("Failed to compile") }; - let account = Account::new_diem_root(); + let account = Account::new_starcoin_root(); let txn = account .transaction() - .write_set(WriteSetPayload::Script { - script: Script::new( - script_body, - vec![], - vec![TransactionArgument::U8Vector(new_key_hash.clone())], - ), - execute_as: *new_account.address(), - }) + .script(Script::new(script_body, vec![], vec![new_key_hash.clone()])) .sequence_number(0) .sign(); executor.new_block(); let output = executor.execute_and_apply(txn); // The transaction should trigger a reconfiguration. - let new_epoch_event_key = diem_types::on_chain_config::new_epoch_event_key(); + let new_epoch_event_key = on_chain_config::new_epoch_event_key(); assert!(output .events() .iter() @@ -151,35 +142,30 @@ fn admin_script_rotate_key_multi_signer() { let script_body = { let code = r#" -import 0x1.DiemAccount; +import 0x1.Account; main(account: signer, auth_key_prefix: vector) { - let rotate_cap: DiemAccount.KeyRotationCapability; + let rotate_cap: Account.KeyRotationCapability; label b0: - rotate_cap = DiemAccount.extract_key_rotation_capability(&account); - DiemAccount.rotate_authentication_key(&rotate_cap, move(auth_key_prefix)); - DiemAccount.restore_key_rotation_capability(move(rotate_cap)); + rotate_cap = Account.extract_key_rotation_capability(&account); + Account.rotate_authentication_key(&rotate_cap, move(auth_key_prefix)); + Account.restore_key_rotation_capability(move(rotate_cap)); return; } "#; let compiler = Compiler { - deps: diem_framework_releases::current_modules().iter().collect(), + deps: stdlib_compiled_modules(StdLibOptions::Compiled(Latest)) + .iter() + .collect(), }; compiler.into_script_blob(code).expect("Failed to compile") }; - let account = Account::new_diem_root(); + let account = Account::new_starcoin_root(); let txn = account .transaction() - .write_set(WriteSetPayload::Script { - script: Script::new( - script_body, - vec![], - vec![TransactionArgument::U8Vector(new_key_hash)], - ), - execute_as: *new_account.address(), - }) + .script(Script::new(script_body, vec![], vec![new_key_hash])) .sequence_number(0) .sign(); executor.new_block(); diff --git a/vm/e2e-testsuite/src/tests/create_account.rs b/vm/e2e-testsuite/src/tests/create_account.rs index 5f488b95ff..c39b10be5a 100644 --- a/vm/e2e-testsuite/src/tests/create_account.rs +++ b/vm/e2e-testsuite/src/tests/create_account.rs @@ -1,13 +1,12 @@ -// Copyright (c) The Diem Core Contributors +// Copyright (c) The Starcoin Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_types::{account_config, transaction::TransactionStatus, vm_status::KeptVMStatus}; -use starcoin_language_e2e_tests::{ - account::{self, Account}, - common_transactions::create_account_txn, - current_function_name, - executor::FakeExecutor, -}; +use move_core_types::vm_status::KeptVMStatus; +use starcoin_language_e2e_tests::account::Account; +use starcoin_language_e2e_tests::common_transactions::create_account_txn; +use starcoin_language_e2e_tests::current_function_name; +use starcoin_language_e2e_tests::executor::FakeExecutor; +use starcoin_vm_types::transaction::TransactionStatus; #[test] fn create_account() { @@ -20,13 +19,7 @@ fn create_account() { // define the arguments to the create account transaction let initial_amount = 0; - let txn = create_account_txn( - &sender, - &new_account, - 0, - initial_amount, - account_config::xus_tag(), - ); + let txn = create_account_txn(&sender, &new_account, 0); // execute transaction let output = executor.execute_transaction(txn); @@ -42,7 +35,7 @@ fn create_account() { .expect("sender must exist"); let updated_receiver_balance = executor - .read_balance_resource(&new_account, account::xus_currency_code()) + .read_balance_resource(&new_account) .expect("receiver balance must exist"); assert_eq!(initial_amount, updated_receiver_balance.coin()); assert_eq!(1, updated_sender.sequence_number()); diff --git a/vm/e2e-testsuite/src/tests/crsn.rs b/vm/e2e-testsuite/src/tests/crsn.rs deleted file mode 100644 index 70bc9628b5..0000000000 --- a/vm/e2e-testsuite/src/tests/crsn.rs +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// SPDX-License-Identifier: Apache-2.0 -use diem_transaction_builder::stdlib; -use diem_types::{account_config, vm_status::StatusCode}; -use starcoin_language_e2e_tests::{ - account::Account, compile::compile_script, current_function_name, executor::FakeExecutor, -}; - -// The CRSN size used throughout the tests -const K: u64 = 10; - -fn init(executor: &mut FakeExecutor) { - let dr = Account::new_diem_root(); - let program = r#" - import 0x1.CRSN; - main(account: signer) { - label b0: - CRSN.allow_crsns(&account); - return; - } - "#; - let script = compile_script(program, vec![]); - let txn = dr.transaction().script(script).sequence_number(0).sign(); - executor.execute_and_apply(txn); -} - -#[test] -fn can_opt_in_to_crsn() { - let mut executor = FakeExecutor::from_genesis_file(); - // set the diem version back - let sender = executor.create_raw_account_data(1_000_010, 0); - executor.add_account_data(&sender); - executor.set_golden_file(current_function_name!()); - init(&mut executor); - - // This should apply - let txn = sender - .account() - .transaction() - .payload(stdlib::encode_opt_in_to_crsn_script_function(K)) - .sequence_number(0) - .sign(); - executor.execute_and_apply(txn); - - let txn = sender - .account() - .transaction() - .payload(stdlib::encode_peer_to_peer_with_metadata_script_function( - account_config::xus_tag(), - *sender.address(), - 100, - vec![], - vec![], - )) - .sequence_number(1) - .sign(); - executor.execute_and_apply(txn); -} - -#[test] -fn crsns_prevent_replay_window_shift() { - let mut executor = FakeExecutor::from_genesis_file(); - // set the diem version back - let sender = executor.create_raw_account_data(1_000_010, 0); - executor.add_account_data(&sender); - executor.set_golden_file(current_function_name!()); - init(&mut executor); - - // This should apply - let txn = sender - .account() - .transaction() - .payload(stdlib::encode_opt_in_to_crsn_script_function(K)) - .sequence_number(0) - .sign(); - executor.execute_and_apply(txn); - - let txn = sender - .account() - .transaction() - .payload(stdlib::encode_peer_to_peer_with_metadata_script_function( - account_config::xus_tag(), - *sender.address(), - 100, - vec![], - vec![], - )) - .sequence_number(1) - .sign(); - executor.execute_and_apply(txn.clone()); - let output = executor.execute_transaction(txn); - assert_eq!( - output.status().status().unwrap_err(), - StatusCode::SEQUENCE_NONCE_INVALID - ); -} - -#[test] -fn crsns_prevent_replay_no_window_shift() { - let mut executor = FakeExecutor::from_genesis_file(); - // set the diem version back - let sender = executor.create_raw_account_data(1_000_010, 0); - executor.add_account_data(&sender); - executor.set_golden_file(current_function_name!()); - init(&mut executor); - - // This should apply - let txn = sender - .account() - .transaction() - .payload(stdlib::encode_opt_in_to_crsn_script_function(K)) - .sequence_number(0) - .sign(); - executor.execute_and_apply(txn); - - let txn = sender - .account() - .transaction() - .payload(stdlib::encode_peer_to_peer_with_metadata_script_function( - account_config::xus_tag(), - *sender.address(), - 100, - vec![], - vec![], - )) - .sequence_number(10) - .sign(); - executor.execute_and_apply(txn.clone()); - - let output = executor.execute_transaction(txn); - assert_eq!( - output.status().status().unwrap_err(), - StatusCode::SEQUENCE_NONCE_INVALID - ); -} - -#[test] -fn crsns_can_be_executed_out_of_order() { - let mut executor = FakeExecutor::from_genesis_file(); - // set the diem version back - let sender = executor.create_raw_account_data(1_000_010, 0); - executor.add_account_data(&sender); - executor.set_golden_file(current_function_name!()); - init(&mut executor); - - // This should apply - let txn = sender - .account() - .transaction() - .payload(stdlib::encode_opt_in_to_crsn_script_function(K)) - .sequence_number(0) - .sign(); - executor.execute_and_apply(txn); - - let mut txns = Vec::new(); - - // worst-case scenario for out-of-order execution - for i in 0..K { - let txn = sender - .account() - .transaction() - .payload(stdlib::encode_peer_to_peer_with_metadata_script_function( - account_config::xus_tag(), - *sender.address(), - 100, - vec![], - vec![], - )) - .sequence_number(K - i) - .sign(); - txns.push(txn); - } - - for output in executor.execute_block_and_keep_vm_status(txns).unwrap() { - assert_eq!(output.0.status_code(), StatusCode::EXECUTED); - } -} - -#[test] -fn force_expiration_of_crsns() { - let mut executor = FakeExecutor::from_genesis_file(); - // set the diem version back - let sender = executor.create_raw_account_data(1_000_010, 0); - executor.add_account_data(&sender); - executor.set_golden_file(current_function_name!()); - init(&mut executor); - - // This should apply - let txn = sender - .account() - .transaction() - .payload(stdlib::encode_opt_in_to_crsn_script_function(K)) - .sequence_number(0) - .sign(); - executor.execute_and_apply(txn); - - // worst-case scenario for out-of-order execution - for i in K / 2..K { - let txn = sender - .account() - .transaction() - .payload(stdlib::encode_peer_to_peer_with_metadata_script_function( - account_config::xus_tag(), - *sender.address(), - 100, - vec![], - vec![], - )) - .sequence_number(i) - .sign(); - executor.execute_and_apply(txn); - } - - let txn = sender - .account() - .transaction() - .payload(stdlib::encode_peer_to_peer_with_metadata_script_function( - account_config::xus_tag(), - *sender.address(), - 100, - vec![], - vec![], - )) - .sequence_number(K + 1) - .sign(); - let output = executor.execute_transaction(txn); - assert_eq!( - output.status().status().unwrap_err(), - StatusCode::SEQUENCE_NONCE_INVALID - ); - - let txn = sender - .account() - .transaction() - .payload(stdlib::encode_force_expire_script_function(2 * K)) - .sequence_number(2) - .sign(); - let output = executor.execute_and_apply(txn); - - // Make sure a force shift event is emitted, that we can deserialize it to the event Rust struct - // and that it is what we expect - let x = &output.events()[0]; - let force_shift = - account_config::force_shift::ForceShiftEvent::try_from_bytes(x.event_data()).unwrap(); - assert_eq!(force_shift.current_min_nonce(), 1); - assert_eq!(force_shift.shift_amount(), 2 * K); - assert_eq!( - force_shift.bits_at_shift(), - vec![false, false, false, false, true, true, true, true, true, false] - ); - - let mut txns = Vec::new(); - - // Check that the old range is expired - for i in 0..2 * K + 1 { - let txn = sender - .account() - .transaction() - .payload(stdlib::encode_peer_to_peer_with_metadata_script_function( - account_config::xus_tag(), - *sender.address(), - 100, - vec![], - vec![], - )) - .sequence_number(i) - .sign(); - txns.push(txn); - } - - for output in executor.execute_block_and_keep_vm_status(txns).unwrap() { - assert_eq!(output.0.status_code(), StatusCode::SEQUENCE_NONCE_INVALID); - } - - let mut txns = Vec::new(); - - // and that the new range works - for i in 0..K { - let txn = sender - .account() - .transaction() - .payload(stdlib::encode_peer_to_peer_with_metadata_script_function( - account_config::xus_tag(), - *sender.address(), - 100, - vec![], - vec![], - )) - .sequence_number(3 * K - i) - .sign(); - - txns.push(txn); - } - - for output in executor.execute_block_and_keep_vm_status(txns).unwrap() { - assert_eq!(output.0.status_code(), StatusCode::EXECUTED); - } -} diff --git a/vm/e2e-testsuite/src/tests/data_store.rs b/vm/e2e-testsuite/src/tests/data_store.rs index 7a0e8ea438..61d18bbc5c 100644 --- a/vm/e2e-testsuite/src/tests/data_store.rs +++ b/vm/e2e-testsuite/src/tests/data_store.rs @@ -1,16 +1,18 @@ -// Copyright (c) The Diem Core Contributors +// Copyright (c) The Starcoin Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_types::{ - transaction::{Module, SignedTransaction, Transaction, TransactionStatus}, - vm_status::KeptVMStatus, -}; use move_binary_format::CompiledModule; use move_bytecode_verifier::verify_module; +use move_core_types::vm_status::KeptVMStatus; use move_ir_compiler::Compiler; use starcoin_language_e2e_tests::{ account::AccountData, compile::compile_script, current_function_name, executor::FakeExecutor, }; +use starcoin_transaction_builder::{stdlib_compiled_modules, StdLibOptions}; +use starcoin_vm_types::genesis_config::StdlibVersion::Latest; +use starcoin_vm_types::transaction::{ + Module, SignedUserTransaction, Transaction, TransactionStatus, +}; #[test] fn move_from_across_blocks() { @@ -203,7 +205,7 @@ fn change_after_move() { executor.apply_write_set(output.write_set()); } -fn add_module_txn(sender: &AccountData, seq_num: u64) -> (CompiledModule, SignedTransaction) { +fn add_module_txn(sender: &AccountData, seq_num: u64) -> (CompiledModule, SignedUserTransaction) { let module_code = format!( " module 0x{}.M {{ @@ -243,7 +245,9 @@ fn add_module_txn(sender: &AccountData, seq_num: u64) -> (CompiledModule, Signed ); let compiler = Compiler { - deps: diem_framework_releases::current_modules().iter().collect(), + deps: stdlib_compiled_modules(StdLibOptions::Compiled(Latest)) + .iter() + .collect(), }; let module = compiler .into_compiled_module(module_code.as_str()) @@ -268,7 +272,7 @@ fn add_resource_txn( sender: &AccountData, seq_num: u64, extra_deps: Vec, -) -> SignedTransaction { +) -> SignedUserTransaction { let program = format!( " import 0x{}.M; @@ -295,7 +299,7 @@ fn remove_resource_txn( sender: &AccountData, seq_num: u64, extra_deps: Vec, -) -> SignedTransaction { +) -> SignedUserTransaction { let program = format!( " import 0x{}.M; @@ -322,7 +326,7 @@ fn borrow_resource_txn( sender: &AccountData, seq_num: u64, extra_deps: Vec, -) -> SignedTransaction { +) -> SignedUserTransaction { let program = format!( " import 0x{}.M; @@ -349,7 +353,7 @@ fn change_resource_txn( sender: &AccountData, seq_num: u64, extra_deps: Vec, -) -> SignedTransaction { +) -> SignedUserTransaction { let program = format!( " import 0x{}.M; diff --git a/vm/e2e-testsuite/src/tests/emergency_admin_script.rs b/vm/e2e-testsuite/src/tests/emergency_admin_script.rs index 82f6fff742..d4cad22d60 100644 --- a/vm/e2e-testsuite/src/tests/emergency_admin_script.rs +++ b/vm/e2e-testsuite/src/tests/emergency_admin_script.rs @@ -1,25 +1,7 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_transaction_builder::stdlib::*; -use diem_types::{ - account_config::diem_root_address, - on_chain_config::{new_epoch_event_key, DIEM_MAX_KNOWN_VERSION}, - transaction::{Transaction, TransactionStatus}, - vm_status::KeptVMStatus, -}; -use diem_writeset_generator::{ - encode_custom_script, encode_halt_network_payload, encode_remove_validators_payload, -}; -use move_core_types::{ - value::{serialize_values, MoveValue}, - vm_status::StatusCode, -}; -use serde_json::json; -use starcoin_language_e2e_tests::{ - common_transactions::peer_to_peer_txn, test_with_different_versions, - versioning::CURRENT_RELEASE_VERSIONS, -}; +use starcoin_language_e2e_tests::test_with_different_versions; #[test] fn validator_batch_remove() { diff --git a/vm/e2e-testsuite/src/tests/execution_strategies.rs b/vm/e2e-testsuite/src/tests/execution_strategies.rs index 1e6d081ae7..53f7c56994 100644 --- a/vm/e2e-testsuite/src/tests/execution_strategies.rs +++ b/vm/e2e-testsuite/src/tests/execution_strategies.rs @@ -1,32 +1,22 @@ -// Copyright (c) The Diem Core Contributors +// Copyright (c) The Starcoin Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_types::{account_config, transaction::SignedTransaction, vm_status::VMStatus}; -use starcoin_language_e2e_tests::{ - account::Account, - common_transactions::create_account_txn, - execution_strategies::{ - basic_strategy::BasicExecutor, - guided_strategy::{ - AnnotatedTransaction, GuidedExecutor, PartitionedGuidedStrategy, - UnPartitionedGuidedStrategy, - }, - multi_strategy::MultiExecutor, - random_strategy::RandomExecutor, - types::Executor, - }, +use move_core_types::vm_status::VMStatus; +use starcoin_language_e2e_tests::account::Account; +use starcoin_language_e2e_tests::common_transactions::create_account_txn; +use starcoin_language_e2e_tests::execution_strategies::basic_strategy::BasicExecutor; +use starcoin_language_e2e_tests::execution_strategies::guided_strategy::{ + AnnotatedTransaction, GuidedExecutor, PartitionedGuidedStrategy, UnPartitionedGuidedStrategy, }; +use starcoin_language_e2e_tests::execution_strategies::multi_strategy::MultiExecutor; +use starcoin_language_e2e_tests::execution_strategies::random_strategy::RandomExecutor; +use starcoin_language_e2e_tests::execution_strategies::types::Executor; +use starcoin_vm_types::transaction::SignedUserTransaction; -fn txn(seq_num: u64) -> SignedTransaction { +fn txn(seq_num: u64) -> SignedUserTransaction { let account = Account::new(); - let diem_root = Account::new_diem_root(); - create_account_txn( - &diem_root, - &account, - seq_num + 1, - 0, - account_config::xus_tag(), - ) + let diem_root = Account::new_starcoin_root(); + create_account_txn(&diem_root, &account, seq_num + 1) } #[test] @@ -111,7 +101,7 @@ fn test_execution_strategies() { println!("==========================================================================="); let block = (0..10).map(txn).collect(); - let mut exec = MultiExecutor::::new(); + let mut exec = MultiExecutor::::new(); exec.add_executor(RandomExecutor::from_os_rng()); exec.add_executor(RandomExecutor::from_os_rng()); exec.add_executor(RandomExecutor::from_os_rng()); diff --git a/vm/e2e-testsuite/src/tests/experimental.rs b/vm/e2e-testsuite/src/tests/experimental.rs index ed2e9a93f7..b960829ddc 100644 --- a/vm/e2e-testsuite/src/tests/experimental.rs +++ b/vm/e2e-testsuite/src/tests/experimental.rs @@ -1,11 +1,11 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_transaction_builder::experimental_stdlib::encode_create_account_script_function; -use diem_types::vm_status::StatusCode; -use starcoin_language_e2e_tests::{ - account::Account, current_function_name, executor::FakeExecutor, -}; +use move_core_types::vm_status::StatusCode; +use starcoin_language_e2e_tests::account::Account; +use starcoin_language_e2e_tests::current_function_name; +use starcoin_language_e2e_tests::executor::FakeExecutor; +use starcoin_transaction_builder::encode_create_account_script_function; // Make sure we can start the experimental genesis #[test] @@ -20,10 +20,10 @@ fn experimental_genesis_execute_txn_successful() { executor.set_golden_file(current_function_name!()); let new_account = executor.create_raw_account(); let new_new_account = executor.create_raw_account(); - let dr_account = Account::new_diem_root(); + let dr_account = Account::new_starcoin_root(); let txn = dr_account .transaction() - .payload(encode_create_account_script_function( + .script_function(encode_create_account_script_function( *new_account.address(), new_account.auth_key_prefix(), )) diff --git a/vm/e2e-testsuite/src/tests/failed_transaction_tests.rs b/vm/e2e-testsuite/src/tests/failed_transaction_tests.rs index 4c15cc877a..204fa703d5 100644 --- a/vm/e2e-testsuite/src/tests/failed_transaction_tests.rs +++ b/vm/e2e-testsuite/src/tests/failed_transaction_tests.rs @@ -1,18 +1,7 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_state_view::StateView; -use diem_types::vm_status::{KeptVMStatus, StatusCode, VMStatus}; -use diem_vm::{ - data_cache::StateViewCache, logging::AdapterLogSchema, - transaction_metadata::TransactionMetadata, DiemVM, -}; -use move_core_types::gas_schedule::{GasAlgebra, GasPrice, GasUnits}; -use move_vm_types::gas_schedule::{zero_cost_schedule, GasStatus}; -use starcoin_language_e2e_tests::{ - account, common_transactions::peer_to_peer_txn, test_with_different_versions, - versioning::CURRENT_RELEASE_VERSIONS, -}; +use starcoin_language_e2e_tests::test_with_different_versions; #[test] fn failed_transaction_cleanup_test() { diff --git a/vm/e2e-testsuite/src/tests/genesis.rs b/vm/e2e-testsuite/src/tests/genesis.rs index f0249bae56..de3923a445 100644 --- a/vm/e2e-testsuite/src/tests/genesis.rs +++ b/vm/e2e-testsuite/src/tests/genesis.rs @@ -1,10 +1,9 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_types::transaction::{Transaction, TransactionStatus, WriteSetPayload}; -use starcoin_language_e2e_tests::{ - common_transactions::peer_to_peer_txn, data_store::GENESIS_CHANGE_SET, executor::FakeExecutor, -}; +use starcoin_language_e2e_tests::common_transactions::peer_to_peer_txn; +use starcoin_language_e2e_tests::executor::FakeExecutor; +use starcoin_vm_types::transaction::Transaction; #[test] fn no_deletion_in_genesis() { diff --git a/vm/e2e-testsuite/src/tests/genesis_initializations.rs b/vm/e2e-testsuite/src/tests/genesis_initializations.rs index 247867dfcf..fba5caaff7 100644 --- a/vm/e2e-testsuite/src/tests/genesis_initializations.rs +++ b/vm/e2e-testsuite/src/tests/genesis_initializations.rs @@ -1,12 +1,12 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_types::account_config; use move_core_types::{ account_address::AccountAddress, value::{serialize_values, MoveValue}, }; use starcoin_language_e2e_tests::executor::FakeExecutor; +use starcoin_types::account_config; #[test] fn test_diem_initialize() { @@ -17,9 +17,7 @@ fn test_diem_initialize() { "Diem", "initialize", vec![], - serialize_values(&vec![ - MoveValue::Signer(account_config::diem_root_address()), - ]), + serialize_values(&vec![MoveValue::Signer(account_config::genesis_address())]), ); assert_eq!(output.unwrap_err().move_abort_code(), Some(5)); @@ -28,9 +26,7 @@ fn test_diem_initialize() { "Roles", "grant_diem_root_role", vec![], - serialize_values(&vec![ - MoveValue::Signer(account_config::diem_root_address()), - ]), + serialize_values(&vec![MoveValue::Signer(account_config::genesis_address())]), ); // Now initialize, it should all succeed. @@ -38,9 +34,7 @@ fn test_diem_initialize() { "Diem", "initialize", vec![], - serialize_values(&vec![ - MoveValue::Signer(account_config::diem_root_address()), - ]), + serialize_values(&vec![MoveValue::Signer(account_config::genesis_address())]), ); // Second time you try though you'll get an already published error with EMODIFY_CAPABILITY @@ -49,9 +43,7 @@ fn test_diem_initialize() { "Diem", "initialize", vec![], - serialize_values(&vec![ - MoveValue::Signer(account_config::diem_root_address()), - ]), + serialize_values(&vec![MoveValue::Signer(account_config::genesis_address())]), ); assert_eq!(output.unwrap_err().move_abort_code(), Some(262)); @@ -66,9 +58,7 @@ fn test_diem_initialize_tc_account() { "Diem", "initialize", vec![], - serialize_values(&vec![ - MoveValue::Signer(account_config::diem_root_address()), - ]), + serialize_values(&vec![MoveValue::Signer(account_config::genesis_address())]), ); assert_eq!(output.unwrap_err().move_abort_code(), Some(5)); @@ -77,9 +67,7 @@ fn test_diem_initialize_tc_account() { "Roles", "grant_diem_root_role", vec![], - serialize_values(&vec![ - MoveValue::Signer(account_config::diem_root_address()), - ]), + serialize_values(&vec![MoveValue::Signer(account_config::genesis_address())]), ); // Grant the TC role @@ -89,7 +77,7 @@ fn test_diem_initialize_tc_account() { vec![], serialize_values(&vec![ MoveValue::Signer(account_config::treasury_compliance_account_address()), - MoveValue::Signer(account_config::diem_root_address()), + MoveValue::Signer(account_config::genesis_address()), ]), ); @@ -110,9 +98,7 @@ fn test_diem_initialize_tc_account() { "Diem", "initialize", vec![], - serialize_values(&vec![ - MoveValue::Signer(account_config::diem_root_address()), - ]), + serialize_values(&vec![MoveValue::Signer(account_config::genesis_address())]), ); // Second time you try though you'll get an already published error with EMODIFY_CAPABILITY @@ -147,18 +133,14 @@ fn test_diem_timestamp_time_has_started() { "DiemTimestamp", "set_time_has_started", vec![], - serialize_values(&vec![ - MoveValue::Signer(account_config::diem_root_address()), - ]), + serialize_values(&vec![MoveValue::Signer(account_config::genesis_address())]), ); let output = executor.try_exec( "DiemTimestamp", "set_time_has_started", vec![], - serialize_values(&vec![ - MoveValue::Signer(account_config::diem_root_address()), - ]), + serialize_values(&vec![MoveValue::Signer(account_config::genesis_address())]), ); assert_eq!(output.unwrap_err().move_abort_code(), Some(1)); @@ -172,18 +154,14 @@ fn test_diem_block_double_init() { "DiemBlock", "initialize_block_metadata", vec![], - serialize_values(&vec![ - MoveValue::Signer(account_config::diem_root_address()), - ]), + serialize_values(&vec![MoveValue::Signer(account_config::genesis_address())]), ); let output = executor.try_exec( "DiemBlock", "initialize_block_metadata", vec![], - serialize_values(&vec![ - MoveValue::Signer(account_config::diem_root_address()), - ]), + serialize_values(&vec![MoveValue::Signer(account_config::genesis_address())]), ); assert_eq!(output.unwrap_err().move_abort_code(), Some(6)); diff --git a/vm/e2e-testsuite/src/tests/mint.rs b/vm/e2e-testsuite/src/tests/mint.rs index d120eb8845..079e9a8e48 100644 --- a/vm/e2e-testsuite/src/tests/mint.rs +++ b/vm/e2e-testsuite/src/tests/mint.rs @@ -1,16 +1,7 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_transaction_builder::stdlib::*; -use diem_types::{ - account_config, - transaction::TransactionStatus, - vm_status::{known_locations, KeptVMStatus}, -}; -use starcoin_language_e2e_tests::{ - account, gas_costs::TXN_RESERVED, test_with_different_versions, - versioning::CURRENT_RELEASE_VERSIONS, -}; +use starcoin_language_e2e_tests::test_with_different_versions; #[test] fn tiered_mint_designated_dealer() { diff --git a/vm/e2e-testsuite/src/tests/mod.rs b/vm/e2e-testsuite/src/tests/mod.rs index 91c856e6a3..821e7d3d98 100644 --- a/vm/e2e-testsuite/src/tests/mod.rs +++ b/vm/e2e-testsuite/src/tests/mod.rs @@ -9,11 +9,11 @@ //! separate binary. The linker ends up repeating a lot of work for each binary to not much //! benefit. -mod account_limits; +// mod account_limits; mod account_universe; mod admin_script; mod create_account; -mod crsn; +// mod crsn; mod data_store; mod emergency_admin_script; mod execution_strategies; diff --git a/vm/e2e-testsuite/src/tests/module_publishing.rs b/vm/e2e-testsuite/src/tests/module_publishing.rs index d8fe81d901..b4be6034c0 100644 --- a/vm/e2e-testsuite/src/tests/module_publishing.rs +++ b/vm/e2e-testsuite/src/tests/module_publishing.rs @@ -1,12 +1,12 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_types::{ - account_config::{self}, - on_chain_config::VMPublishingOption, - transaction::TransactionStatus, - vm_status::{KeptVMStatus, StatusCode}, -}; +// use diem_types::{ +// account_config::{self}, +// on_chain_config::VMPublishingOption, +// transaction::TransactionStatus, +// vm_status::{KeptVMStatus, StatusCode}, +// }; use starcoin_language_e2e_tests::{ account::Account, assert_prologue_parity, compile::compile_module, current_function_name, executor::FakeExecutor, transaction_status_eq, @@ -306,7 +306,7 @@ pub fn test_publishing_no_modules_non_allowlist_script_proper_sender() { executor.set_golden_file(current_function_name!()); // create a transaction trying to publish a new module. - let sender = Account::new_diem_root(); + let sender = Account::new_starcoin_root(); let program = String::from( " @@ -335,7 +335,7 @@ pub fn test_publishing_no_modules_proper_sender() { executor.set_golden_file(current_function_name!()); // create a transaction trying to publish a new module. - let sender = Account::new_diem_root(); + let sender = Account::new_starcoin_root(); let program = String::from( " diff --git a/vm/e2e-testsuite/src/tests/multi_agent.rs b/vm/e2e-testsuite/src/tests/multi_agent.rs index 93522c26cc..1ed345d040 100644 --- a/vm/e2e-testsuite/src/tests/multi_agent.rs +++ b/vm/e2e-testsuite/src/tests/multi_agent.rs @@ -3,20 +3,6 @@ //! Tests for multi-agent transactions. -use diem_transaction_builder::stdlib::*; -use diem_types::{ - account_config, test_helpers::transaction_test_helpers, transaction::TransactionStatus, - vm_status::KeptVMStatus, -}; -use starcoin_language_e2e_tests::{ - account::{self, xdx_currency_code, xus_currency_code, Account}, - common_transactions::{ - multi_agent_mint_txn, multi_agent_p2p_txn, multi_agent_swap_script, multi_agent_swap_txn, - }, - current_function_name, - executor::FakeExecutor, -}; - #[test] fn multi_agent_mint() { let mut executor = FakeExecutor::from_genesis_file(); diff --git a/vm/e2e-testsuite/src/tests/on_chain_configs.rs b/vm/e2e-testsuite/src/tests/on_chain_configs.rs index 49c912c2c8..1ee00cf5d1 100644 --- a/vm/e2e-testsuite/src/tests/on_chain_configs.rs +++ b/vm/e2e-testsuite/src/tests/on_chain_configs.rs @@ -148,7 +148,7 @@ fn update_script_allow_list() { // create a FakeExecutor with a genesis from file let mut executor = FakeExecutor::allowlist_genesis(); executor.set_golden_file(current_function_name!()); - let dr = Account::new_diem_root(); + let dr = Account::new_starcoin_root(); // create and publish a sender with 5_000_000 coins and a receiver with 0 coins let sender = executor.create_raw_account_data(5_000_000, 10); executor.add_account_data(&sender); diff --git a/vm/e2e-testsuite/src/tests/parallel_execution.rs b/vm/e2e-testsuite/src/tests/parallel_execution.rs index aee05760d8..15f7d27285 100644 --- a/vm/e2e-testsuite/src/tests/parallel_execution.rs +++ b/vm/e2e-testsuite/src/tests/parallel_execution.rs @@ -1,22 +1,9 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use crate::tests::peer_to_peer::{check_and_apply_transfer_output, create_cyclic_transfers}; -use starcoin_crypto::{ed25519::Ed25519PrivateKey, HashValue, PrivateKey, Uniform}; -use diem_types::{ - block_metadata::BlockMetadata, - on_chain_config::{OnChainConfig, ParallelExecutionConfig, ValidatorSet}, - transaction::{ - authenticator::AuthenticationKey, Script, Transaction, TransactionArgument, - TransactionStatus, WriteSetPayload, - }, - vm_status::{KeptVMStatus, StatusCode}, -}; -use starcoin_vm::parallel_executor::ParallelDiemVM; -use move_ir_compiler::Compiler; -use starcoin_language_e2e_tests::{ - account, common_transactions::rotate_key_txn, executor::FakeExecutor, -}; +use crate::tests::peer_to_peer::create_cyclic_transfers; +use starcoin_language_e2e_tests::executor::FakeExecutor; +use starcoin_vm_types::transaction::Transaction; #[test] fn peer_to_peer_with_prologue_parallel() { @@ -195,7 +182,7 @@ fn parallel_execution_with_bad_config() { // insert a block prologue transaction let (txns_info, transfer_txns) = create_cyclic_transfers(&executor, &accounts, transfer_amount); - let diem_root = account::Account::new_diem_root(); + let diem_root = account::Account::new_starcoin_root(); let seq_num = executor .read_account_resource_at_address(diem_root.address()) .unwrap() diff --git a/vm/e2e-testsuite/src/tests/peer_to_peer.rs b/vm/e2e-testsuite/src/tests/peer_to_peer.rs index 25225cad6b..3d1152aab9 100644 --- a/vm/e2e-testsuite/src/tests/peer_to_peer.rs +++ b/vm/e2e-testsuite/src/tests/peer_to_peer.rs @@ -1,19 +1,8 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_types::{ - account_config::{ReceivedPaymentEvent, SentPaymentEvent}, - transaction::{SignedTransaction, TransactionOutput, TransactionStatus}, - vm_status::{known_locations, KeptVMStatus}, -}; -use starcoin_language_e2e_tests::{ - account::{self, Account}, - common_transactions::peer_to_peer_txn, - executor::FakeExecutor, - test_with_different_versions, transaction_status_eq, - versioning::CURRENT_RELEASE_VERSIONS, -}; -use std::{convert::TryFrom, time::Instant}; +use starcoin_language_e2e_tests::account::Account; +use starcoin_language_e2e_tests::executor::FakeExecutor; #[test] fn single_peer_to_peer_with_event() { diff --git a/vm/e2e-testsuite/src/tests/rotate_key.rs b/vm/e2e-testsuite/src/tests/rotate_key.rs index 7a5269c718..54bba22058 100644 --- a/vm/e2e-testsuite/src/tests/rotate_key.rs +++ b/vm/e2e-testsuite/src/tests/rotate_key.rs @@ -1,16 +1,16 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use starcoin_crypto::{ - ed25519::Ed25519PrivateKey, - multi_ed25519::{MultiEd25519PublicKey, MultiEd25519Signature}, - PrivateKey, SigningKey, Uniform, -}; use diem_keygen::KeyGen; use diem_types::{ transaction::{authenticator::AuthenticationKey, SignedTransaction, TransactionStatus}, vm_status::{KeptVMStatus, StatusCode}, }; +use starcoin_crypto::{ + ed25519::Ed25519PrivateKey, + multi_ed25519::{MultiEd25519PublicKey, MultiEd25519Signature}, + PrivateKey, SigningKey, Uniform, +}; use starcoin_language_e2e_tests::{ account, common_transactions::{raw_rotate_key_txn, rotate_key_txn}, diff --git a/vm/e2e-testsuite/src/tests/transaction_builder.rs b/vm/e2e-testsuite/src/tests/transaction_builder.rs index 8fdb897761..7f2b0acfa9 100644 --- a/vm/e2e-testsuite/src/tests/transaction_builder.rs +++ b/vm/e2e-testsuite/src/tests/transaction_builder.rs @@ -10,6 +10,16 @@ use starcoin_crypto::{ed25519::Ed25519PrivateKey, traits::SigningKey, PrivateKey, Uniform}; // use diem_keygen::KeyGen; +use move_core_types::language_storage::TypeTag; +use starcoin_language_e2e_tests::{ + account::{self, Account}, + common_transactions::rotate_key_txn, + //currencies, current_function_name, + executor::FakeExecutor, + gas_costs, + test_with_different_versions, + versioning::CURRENT_RELEASE_VERSIONS, +}; use starcoin_transaction_builder::stdlib::*; use starcoin_types::{ account_address::AccountAddress, @@ -20,15 +30,6 @@ use starcoin_types::{ }, vm_status::{KeptVMStatus, StatusCode}, }; -use move_core_types::language_storage::TypeTag; -use starcoin_language_e2e_tests::{ - account::{self, Account}, - common_transactions::rotate_key_txn, - //currencies, current_function_name, - executor::FakeExecutor, - gas_costs, test_with_different_versions, - versioning::CURRENT_RELEASE_VERSIONS, -}; const XUS_THRESHOLD: u64 = 10_000_000_000 / 5; const BAD_METADATA_SIGNATURE_ERROR_CODE: u64 = 775; @@ -1173,7 +1174,7 @@ fn add_child_currencies() { let vasp_b_child1 = executor.create_raw_account(); let vasp_b_child2 = executor.create_raw_account(); let blessed = Account::new_blessed_tc(); - let dr_account = Account::new_diem_root(); + let dr_account = Account::new_starcoin_root(); let tc_sequence_number = 0; currencies::add_currency_to_system(&mut executor, "COIN", &dr_account, 0); diff --git a/vm/e2e-testsuite/src/tests/transaction_fees.rs b/vm/e2e-testsuite/src/tests/transaction_fees.rs index 5be3c27abd..0ac7e08932 100644 --- a/vm/e2e-testsuite/src/tests/transaction_fees.rs +++ b/vm/e2e-testsuite/src/tests/transaction_fees.rs @@ -1,7 +1,6 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use starcoin_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, Uniform}; use diem_framework_releases::legacy::transaction_scripts::LegacyStdlibScript; use diem_transaction_builder::stdlib::*; use diem_types::{ @@ -13,6 +12,7 @@ use move_core_types::{ identifier::Identifier, language_storage::{StructTag, TypeTag}, }; +use starcoin_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, Uniform}; use starcoin_language_e2e_tests::{ test_with_different_versions, versioning::CURRENT_RELEASE_VERSIONS, }; diff --git a/vm/e2e-testsuite/src/tests/transaction_fuzzer.rs b/vm/e2e-testsuite/src/tests/transaction_fuzzer.rs index 6ae35e3641..aacea08076 100644 --- a/vm/e2e-testsuite/src/tests/transaction_fuzzer.rs +++ b/vm/e2e-testsuite/src/tests/transaction_fuzzer.rs @@ -19,7 +19,7 @@ proptest! { ) { let executor = FakeExecutor::from_genesis_file(); let accounts = vec![ - (Account::new_diem_root(), 0), + (Account::new_starcoin_root(), 0), (Account::new_blessed_tc(), 0), ]; let num_accounts = accounts.len(); @@ -43,7 +43,7 @@ proptest! { ) { let mut executor = FakeExecutor::from_genesis_file(); let mut accounts = vec![]; - let diem_root = Account::new_diem_root(); + let diem_root = Account::new_starcoin_root(); let coins = vec![account::xus_currency_code()]; // Create a number of accounts for i in 0..10 { diff --git a/vm/e2e-testsuite/src/tests/validator_set_management.rs b/vm/e2e-testsuite/src/tests/validator_set_management.rs index 0904908c6d..3dad837aaf 100644 --- a/vm/e2e-testsuite/src/tests/validator_set_management.rs +++ b/vm/e2e-testsuite/src/tests/validator_set_management.rs @@ -125,7 +125,7 @@ fn validator_add_max_number() { executor.set_golden_file(current_function_name!()); - let output = try_add_validator(&mut executor, &Account::new_diem_root(), 0); + let output = try_add_validator(&mut executor, &Account::new_starcoin_root(), 0); assert_aborted_with(output, 1800); } diff --git a/vm/e2e-testsuite/src/tests/vasps.rs b/vm/e2e-testsuite/src/tests/vasps.rs index ef4f775a37..0f2e634413 100644 --- a/vm/e2e-testsuite/src/tests/vasps.rs +++ b/vm/e2e-testsuite/src/tests/vasps.rs @@ -3,7 +3,6 @@ #![forbid(unsafe_code)] -use starcoin_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, Uniform}; use diem_transaction_builder::stdlib::*; use diem_types::{ account_config, @@ -14,6 +13,7 @@ use move_core_types::{ value::{serialize_values, MoveValue}, vm_status::VMStatus, }; +use starcoin_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, Uniform}; use starcoin_language_e2e_tests::{ test_with_different_versions, versioning::CURRENT_RELEASE_VERSIONS, }; diff --git a/vm/e2e-testsuite/src/tests/verify_txn.rs b/vm/e2e-testsuite/src/tests/verify_txn.rs index d4d4df9c40..22054a18e8 100644 --- a/vm/e2e-testsuite/src/tests/verify_txn.rs +++ b/vm/e2e-testsuite/src/tests/verify_txn.rs @@ -1,52 +1,16 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -// use starcoin_crypto::{ -// ed25519::{Ed25519PrivateKey, Ed25519PublicKey}, -// multi_ed25519::{MultiEd25519PrivateKey, MultiEd25519PublicKey}, -// PrivateKey, SigningKey, Uniform, -// }; -// use starcoin_framework_releases::legacy::transaction_scripts::LegacyStdlibScript; -// use starcoin_keygen::KeyGen; -// use starcoin_transaction_builder::{ -// stdlib as transaction_builder, stdlib::encode_peer_to_peer_with_metadata_script, -// }; -// use starcoin_types::{ -// account_address::AccountAddress, -// account_config, -// chain_id::ChainId, -// on_chain_config::VMPublishingOption, -// test_helpers::transaction_test_helpers, -// transaction::{ -// authenticator::{AccountAuthenticator, AuthenticationKey, MAX_NUM_OF_SIGS}, -// RawTransactionWithData, Script, SignedTransaction, TransactionArgument, TransactionPayload, -// TransactionStatus, WriteSetPayload, -// }, -// vm_status::{KeptVMStatus, StatusCode}, -// }; -// use move_binary_format::file_format::CompiledModule; -// use move_core_types::{ -// gas_schedule::{GasAlgebra, GasConstants, MAX_TRANSACTION_SIZE_IN_BYTES}, -// identifier::Identifier, -// language_storage::{StructTag, TypeTag}, -// value::{serialize_values, MoveValue}, -// }; -// use move_ir_compiler::Compiler; -// use starcoin_language_e2e_tests::{ -// account::Account, -// assert_prologue_disparity, assert_prologue_parity, -// common_transactions::{ -// multi_agent_mint_script, multi_agent_swap_script, raw_multi_agent_swap_txn, rotate_key_txn, -// }, -// compile::compile_module, -// current_function_name, -// executor::FakeExecutor, -// gas_costs, test_with_different_versions, transaction_status_eq, -// versioning::CURRENT_RELEASE_VERSIONS, -// }; - +use move_binary_format::CompiledModule; +use move_core_types::account_address::AccountAddress; +use move_ir_compiler::Compiler; +use starcoin_crypto::ed25519::Ed25519PrivateKey; +use starcoin_crypto::Uniform; +use starcoin_language_e2e_tests::account::Account; use starcoin_language_e2e_tests::executor::FakeExecutor; -use starcoin_language_e2e_tests::test_with_different_versions; +use starcoin_language_e2e_tests::{ + assert_prologue_parity, current_function_name, test_with_different_versions, +}; #[test] fn verify_signature() { @@ -985,7 +949,7 @@ pub fn test_no_publishing_diem_root_sender() { executor.set_golden_file(current_function_name!()); // create a transaction trying to publish a new module. - let sender = Account::new_diem_root(); + let sender = Account::new_starcoin_root(); let module = String::from( " @@ -1541,7 +1505,7 @@ pub fn publish_and_register_new_currency() { executor.set_golden_file(current_function_name!()); // create a transaction trying to publish a new module. - let sender = Account::new_diem_root(); + let sender = Account::new_starcoin_root(); let tc_account = Account::new_blessed_tc(); let module = r#" diff --git a/vm/e2e-testsuite/src/tests/write_set.rs b/vm/e2e-testsuite/src/tests/write_set.rs index cfb65e7352..eb5f373f39 100644 --- a/vm/e2e-testsuite/src/tests/write_set.rs +++ b/vm/e2e-testsuite/src/tests/write_set.rs @@ -1,7 +1,6 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use starcoin_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, Uniform}; use diem_types::{ access_path::AccessPath, account_config::{xus_tag, CORE_CODE_ADDRESS}, @@ -18,6 +17,7 @@ use move_core_types::{ identifier::Identifier, language_storage::{ResourceKey, StructTag}, }; +use starcoin_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, Uniform}; use starcoin_language_e2e_tests::{ account, assert_prologue_parity, common_transactions::rotate_key_txn, test_with_different_versions, transaction_status_eq, versioning::CURRENT_RELEASE_VERSIONS, diff --git a/vm/e2e-testsuite/src/tests/writeset_builder.rs b/vm/e2e-testsuite/src/tests/writeset_builder.rs index 2c88eb3b7b..4e74344eed 100644 --- a/vm/e2e-testsuite/src/tests/writeset_builder.rs +++ b/vm/e2e-testsuite/src/tests/writeset_builder.rs @@ -20,7 +20,7 @@ fn build_upgrade_writeset() { executor.set_golden_file(current_function_name!()); // create a transaction trying to publish a new module. - let genesis_account = Account::new_diem_root(); + let genesis_account = Account::new_starcoin_root(); let program = String::from( " @@ -38,7 +38,7 @@ fn build_upgrade_writeset() { }; let change_set = { let (version_writes, events) = build_changeset(executor.get_state_view(), |session| { - session.set_diem_version(11); + session.set_starcoin_version(11); }) .into_inner(); let mut writeset = version_writes.into_mut(); diff --git a/vm/parallel-executor/src/scheduler.rs b/vm/parallel-executor/src/scheduler.rs new file mode 100644 index 0000000000..0611569e09 --- /dev/null +++ b/vm/parallel-executor/src/scheduler.rs @@ -0,0 +1,619 @@ +// Copyright (c) The Starcoin Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use crossbeam::utils::CachePadded; +use starcoin_infallible::Mutex; +use std::{ + cmp::min, + hint, + sync::{ + atomic::{AtomicBool, AtomicUsize, Ordering}, + Arc, Condvar, + }, +}; + +// Type aliases. +pub type TxnIndex = usize; +pub type Incarnation = usize; +pub type Version = (TxnIndex, Incarnation); +type DependencyCondvar = Arc<(Mutex, Condvar)>; + +// A struct to track the number of active tasks in the scheduler using RAII. +pub struct TaskGuard<'a> { + counter: &'a AtomicUsize, +} + +impl<'a> TaskGuard<'a> { + pub fn new(counter: &'a AtomicUsize) -> Self { + counter.fetch_add(1, Ordering::SeqCst); + Self { counter } + } +} + +impl Drop for TaskGuard<'_> { + fn drop(&mut self) { + assert!(self.counter.fetch_sub(1, Ordering::SeqCst) > 0); + } +} + +/// A holder for potential task returned from the Scheduler. ExecutionTask and ValidationTask +/// each contain a version of transaction that must be executed or validated, respectively. +/// NoTask holds no task (similar None if we wrapped tasks in Option), and Done implies that +/// there are no more tasks and the scheduler is done. +pub enum SchedulerTask<'a> { + ExecutionTask(Version, Option, TaskGuard<'a>), + ValidationTask(Version, TaskGuard<'a>), + NoTask, + Done, +} + +/// All possible statuses for each transaction. Each status contains the latest incarnation number. +/// +/// 'ReadyToExecute' means that the corresponding incarnation should be executed and the scheduler +/// must eventually create a corresponding execution task. The scheduler ensures that exactly one +/// execution task gets created, changing the status to 'Executing' in the process. If a dependency +/// condition variable is set, then an execution of a prior incarnation is waiting on it with +/// a read dependency resolved (when dependency was encountered, the status changed to Suspended, +/// and suspended changed to ReadyToExecute when the dependency finished its execution). In this case +/// the caller need not create a new execution task, but just nofity the suspended execution. +/// +/// 'Executing' status of an incarnation turns into 'Executed' if the execution task finishes, or +/// if a dependency is encountered, it becomes 'ReadyToExecute(incarnation + 1)' once the +/// dependency is resolved. An 'Executed' status allows creation of validation tasks for the +/// corresponding incarnation, and a validation failure leads to an abort. The scheduler ensures +/// that there is exactly one abort, changing the status to 'Aborting' in the process. Once the +/// thread that successfully aborted performs everything that's required, it sets the status +/// to 'ReadyToExecute(incarnation + 1)', allowing the scheduler to create an execution +/// task for the next incarnation of the transaction. +/// +/// Status transition diagram: +/// Ready(i) +/// | try_incarnate (incarnate successfully) +/// | +/// ↓ suspend (waiting on dependency) resume +/// Executing(i) -----------------------------> Suspended(i) ------------> Ready(i) +/// | +/// | finish_execution +/// ↓ +/// Executed(i) (pending for (re)validations) +/// | +/// | try_abort (abort successfully) +/// ↓ finish_abort +/// Aborting(i) ---------------------------------------------------------> Ready(i+1) +/// +#[derive(Debug)] +enum TransactionStatus { + ReadyToExecute(Incarnation, Option), + Executing(Incarnation), + Suspended(Incarnation, DependencyCondvar), + Executed(Incarnation), + Aborting(Incarnation), +} + +impl PartialEq for TransactionStatus { + fn eq(&self, other: &Self) -> bool { + use TransactionStatus::*; + match (self, other) { + (&ReadyToExecute(ref a, _), &ReadyToExecute(ref b, _)) + | (&Executing(ref a), &Executing(ref b)) + | (&Suspended(ref a, _), &Suspended(ref b, _)) + | (&Executed(ref a), &Executed(ref b)) + | (&Aborting(ref a), &Aborting(ref b)) => a == b, + _ => false, + } + } +} + +pub struct Scheduler { + /// Number of txns to execute, immutable. + num_txns: usize, + + /// A shared index that tracks the minimum of all transaction indices that require execution. + /// The threads increment the index and attempt to create an execution task for the corresponding + /// transaction, if the status of the txn is 'ReadyToExecute'. This implements a counting-based + /// concurrent ordered set. It is reduced as necessary when transactions become ready to be + /// executed, in particular, when execution finishes and dependencies are resolved. + execution_idx: AtomicUsize, + /// A shared index that tracks the minimum of all transaction indices that require validation. + /// The threads increment the index and attempt to create a validation task for the corresponding + /// transaction, if the status of the txn is 'Executed'. This implements a counting-based + /// concurrent ordered set. It is reduced as necessary when transactions require validation, + /// in particular, after aborts and executions that write outside of the write set of the + /// same transaction's previous incarnation. + validation_idx: AtomicUsize, + /// The the number of times execution_idx and validation_idx are decreased. + decrease_cnt: AtomicUsize, + + /// Number of tasks used to track when transactions can be committed, incremented / decremented + /// as new validation or execution tasks are created and completed. + num_active_tasks: AtomicUsize, + /// Shared marker that is set when a thread detects that all txns can be committed. + done_marker: AtomicBool, + + /// An index i maps to indices of other transactions that depend on transaction i, i.e. they + /// should be re-executed once transaction i's next incarnation finishes. + txn_dependency: Vec>>>, + /// An index i maps to the most up-to-date status of transaction i. + txn_status: Vec>>, +} + +/// Public Interfaces for the Scheduler +impl Scheduler { + pub fn new(num_txns: usize) -> Self { + Self { + num_txns, + execution_idx: AtomicUsize::new(0), + validation_idx: AtomicUsize::new(0), + decrease_cnt: AtomicUsize::new(0), + num_active_tasks: AtomicUsize::new(0), + done_marker: AtomicBool::new(false), + txn_dependency: (0..num_txns) + .map(|_| CachePadded::new(Mutex::new(Vec::new()))) + .collect(), + txn_status: (0..num_txns) + .map(|_| CachePadded::new(Mutex::new(TransactionStatus::ReadyToExecute(0, None)))) + .collect(), + } + } + + /// Return the number of transactions to be executed from the block. + pub fn num_txn_to_execute(&self) -> usize { + self.num_txns + } + + /// Try to abort version = (txn_idx, incarnation), called upon validation failure. + /// When the invocation manages to update the status of the transaction, it changes + /// Executed(incarnation) => Aborting(incarnation), it returns true. Otherwise, + /// returns false. Since incarnation numbers never decrease, this also ensures + /// that the same version may not successfully abort more than once. + pub fn try_abort(&self, txn_idx: TxnIndex, incarnation: Incarnation) -> bool { + // println!( + // "{:?} - Scheduler::try_abort | Entered, txn_idx: {:?}, incarnation: {:?}", + // thread::current().id(), + // txn_idx, + // incarnation + // ); + // lock the status. + let mut status = self.txn_status[txn_idx].lock(); + // println!( + // "{:?} - Scheduler::try_abort | Status: {:?} ", + // thread::current().id(), + // status + // ); + + if *status == TransactionStatus::Executed(incarnation) { + *status = TransactionStatus::Aborting(incarnation); + // println!( + // "{:?} - Scheduler::try_abort | Exited, status == Executed", + // thread::current().id() + // ); + true + } else { + // println!( + // "{:?} - Scheduler::try_abort | Exited, status != Executed", + // thread::current().id() + // ); + false + } + } + + /// Return the next task for the thread. + pub fn next_task(&self) -> SchedulerTask { + // println!("{:?} - Scheduler::next_task | Entered", thread::current().id()); + loop { + if self.done() { + // No more tasks. + // println!("{:?} - Scheduler::next_task | Exited, has SchedulerTask::Done", thread::current().id()); + return SchedulerTask::Done; + } + + let idx_to_validate = self.validation_idx.load(Ordering::SeqCst); + let idx_to_execute = self.execution_idx.load(Ordering::SeqCst); + + //println!("{:?} - Scheduler::next_task | idx_to_validate: {}, idx_to_execute: {}", thread::current().id(), idx_to_validate, idx_to_execute); + + if idx_to_validate < idx_to_execute { + if let Some((version_to_validate, guard)) = self.try_validate_next_version() { + // println!("{:?} - Scheduler::next_task | Exited: SchedulerTask::ValidationTask", thread::current().id()); + return SchedulerTask::ValidationTask(version_to_validate, guard); + } + } else if let Some((version_to_execute, maybe_condvar, guard)) = + self.try_execute_next_version() + { + // println!("{:?} - Scheduler::next_task | Exited: SchedulerTask::ExecutionTask", thread::current().id()); + return SchedulerTask::ExecutionTask(version_to_execute, maybe_condvar, guard); + } + } + } + + /// When a txn depends on another txn, adds it to the dependency list of the other txn. + /// Returns true if successful, or false, if the dependency got resolved in the meantime. + /// If true is returned, Scheduler guarantees that later (dep_txn_idx will finish execution) + /// transaction txn_idx will be resumed, and corresponding execution task created. + /// If false is returned, it is caller's responsibility to repeat the read that caused the + /// dependency and continue the ongoing execution of txn_idx. + pub fn wait_for_dependency( + &self, + txn_idx: TxnIndex, + dep_txn_idx: TxnIndex, + ) -> Option { + // Note: Could pre-check that txn dep_txn_idx isn't in an executed state, but the caller + // usually has just observed the read dependency. + + // println!( + // "{:?} - Scheduler::wait_for_dependency | Entered, txn_idx: {:#?}, dep_txn_idx: {:#?}", + // thread::current().id(), + // txn_idx, + // dep_txn_idx + // ); + + // Create a condition variable associated with the dependency. + let dep_condvar = Arc::new((Mutex::new(false), Condvar::new())); + + let mut stored_deps = self.txn_dependency[dep_txn_idx].lock(); + + { + if self.is_executed(dep_txn_idx).is_some() { + // Current status of dep_txn_idx is 'executed', so the dependency got resolved. + // To avoid zombie dependency (and losing liveness), must return here and + // not add a (stale) dependency. + + // Note: acquires (a different, status) mutex, while holding (dependency) mutex. + // Only place in scheduler where a thread may hold >1 mutexes, hence, such + // acquisitions always happens in the same order (this function), may not deadlock. + + // println!( + // "{:?} - Scheduler::wait_for_dependency | Exited, return None", + // thread::current().id(), + // ); + return None; + } + + self.suspend(txn_idx, dep_condvar.clone()); + + // Safe to add dependency here (still holding the lock) - finish_execution of txn + // dep_txn_idx is guaranteed to acquire the same lock later and clear the dependency. + stored_deps.push(txn_idx); + } + + // println!("{:?} - Scheduler::wait_for_dependency | Exited, return Some(dep_condvar), condvar index: {:?}", thread::current().id(), txn_idx); + Some(dep_condvar) + } + + /// After txn is executed, schedule its dependencies for re-execution. + /// If revalidate_suffix is true, decrease validation_idx to schedule all higher transactions + /// for (re-)validation. Otherwise, in some cases (if validation_idx not already lower), + /// return a validation task of the transaction to the caller (otherwise NoTask). + pub fn finish_execution<'a>( + &self, + txn_idx: TxnIndex, + incarnation: Incarnation, + revalidate_suffix: bool, + guard: TaskGuard<'a>, + ) -> SchedulerTask<'a> { + // println!( + // "{:?} - Scheduler::finish_execution | Entered, txn_id: {:?}, incarnation: {:?} ", + // thread::current().id(), + // txn_idx, + // incarnation + // ); + + self.set_executed_status(txn_idx, incarnation); + + let txn_deps: Vec = { + let mut stored_deps = self.txn_dependency[txn_idx].lock(); + // Holding the lock, take dependency vector. + std::mem::take(&mut stored_deps) + }; + + // Mark dependencies as resolved and find the minimum index among them. + let min_dep = txn_deps + .into_iter() + .map(|dep| { + // Mark the status of dependencies as 'ReadyToExecute' since dependency on + // transaction txn_idx is now resolved. + self.resume(dep); + + dep + }) + .min(); + + if let Some(execution_target_idx) = min_dep { + // Decrease the execution index as necessary to ensure resolved dependencies + // get a chance to be re-executed. + self.decrease_execution_idx(execution_target_idx); + } + + // If validation_idx is already lower than txn_idx, all required transactions will be + // considered for validation, and there is nothing to do. + if self.validation_idx.load(Ordering::SeqCst) > txn_idx { + if revalidate_suffix { + // The transaction execution required revalidating all higher txns (not + // only itself), currently happens when incarnation writes to a new path + // (w.r.t. the write-set of its previous completed incarnation). + self.decrease_validation_idx(txn_idx); + } else { + // Only transaction txn_idx requires validation. Return validation task + // back to the caller. No need to change active tasks (-1 +1= 0) + // println!( + // "{:?} - Scheduler::finish_execution | Exited, ValidationTask", + // thread::current().id() + // ); + + return SchedulerTask::ValidationTask((txn_idx, incarnation), guard); + } + } + + // println!( + // "{:?} - Scheduler::finish_execution | Exited, NoTask", + // thread::current().id() + // ); + + SchedulerTask::NoTask + } + + /// Finalize a validation task of version (txn_idx, incarnation). In some cases, + /// may return a re-execution task back to the caller (otherwise, NoTask). + pub fn finish_abort<'a>( + &self, + txn_idx: TxnIndex, + incarnation: Incarnation, + guard: TaskGuard<'a>, + ) -> SchedulerTask<'a> { + self.set_aborted_status(txn_idx, incarnation); + + // Schedule strictly higher txns for validation + // (txn_idx needs to be re-executed first). + self.decrease_validation_idx(txn_idx + 1); + + // txn_idx must be re-executed, and if execution_idx is lower, it will be. + if self.execution_idx.load(Ordering::SeqCst) > txn_idx { + // Optimization: execution_idx is higher than txn_idx, but decreasing it may + // lead to wasted work for all indices between txn_idx and execution_idx. + // Instead, attempt to create a new incarnation and return the corresponding + // re-execution task back to the caller. If incarnation fails, there is + // nothing to do, as another thread must have succeeded to incarnate and + // obtain the task for re-execution. + if let Some((new_incarnation, maybe_condvar)) = self.try_incarnate(txn_idx) { + // println!( + // "{:?} - Scheduler::finish_abort | Exited, ExecutionTask", + // thread::current().id() + // ); + + return SchedulerTask::ExecutionTask( + (txn_idx, new_incarnation), + maybe_condvar, + guard, + ); + } + } + + // println!( + // "{:?} - Scheduler::finish_abort | Exited, NoTask", + // thread::current().id() + // ); + + SchedulerTask::NoTask + } +} + +/// Public functions of the Scheduler +impl Scheduler { + /// Decreases the validation index, increases the decrease counter if it actually decreased. + fn decrease_validation_idx(&self, target_idx: TxnIndex) { + if self.validation_idx.fetch_min(target_idx, Ordering::SeqCst) > target_idx { + self.decrease_cnt.fetch_add(1, Ordering::SeqCst); + } + } + + /// Decreases the execution index, increases the decrease counter if it actually decreased. + fn decrease_execution_idx(&self, target_idx: TxnIndex) { + if self.execution_idx.fetch_min(target_idx, Ordering::SeqCst) > target_idx { + self.decrease_cnt.fetch_add(1, Ordering::SeqCst); + } + } + + /// Try and incarnate a transaction. Only possible when the status is + /// ReadyToExecute(incarnation), in which case Some(incarnation) is returned and the + /// status is (atomically, due to the mutex) updated to Executing(incarnation). + /// An unsuccessful incarnation returns None. Since incarnation numbers never decrease + /// for each transaction, incarnate function may not succeed more than once per version. + fn try_incarnate(&self, txn_idx: TxnIndex) -> Option<(Incarnation, Option)> { + if txn_idx >= self.txn_status.len() { + return None; + } + + let mut status = self.txn_status[txn_idx].lock(); + if let TransactionStatus::ReadyToExecute(incarnation, maybe_condvar) = &*status { + let ret = (*incarnation, maybe_condvar.clone()); + *status = TransactionStatus::Executing(*incarnation); + Some(ret) + } else { + None + } + } + + /// If the status of transaction is Executed(incarnation), returns Some(incarnation), + /// otherwise returns None. Useful to determine when a transaction can be validated, + /// and to avoid a race in dependency resolution. + fn is_executed(&self, txn_idx: TxnIndex) -> Option { + if txn_idx >= self.txn_status.len() { + return None; + } + + let status = self.txn_status[txn_idx].lock(); + if let TransactionStatus::Executed(incarnation) = *status { + Some(incarnation) + } else { + None + } + } + + /// Grab an index to try and validate next (by fetch-and-incrementing validation_idx). + /// - If the index is out of bounds, return None (and invoke a check of whethre + /// all txns can be committed). + /// - If the transaction is ready for validation (EXECUTED state), return the version + /// to the caller together with a guard to be used for the corresponding ValidationTask. + /// - Otherwise, return None. + fn try_validate_next_version(&self) -> Option<(Version, TaskGuard)> { + let idx_to_validate = self.validation_idx.load(Ordering::SeqCst); + + if idx_to_validate >= self.num_txns { + if !self.check_done() { + // Avoid pointlessly spinning, and give priority to other threads that may + // be working to finish the remaining tasks. + hint::spin_loop(); + } + return None; + } + + // Must create guard before incremeting validation_idx. + let guard = TaskGuard::new(&self.num_active_tasks); + let idx_to_validate = self.validation_idx.fetch_add(1, Ordering::SeqCst); + + // If incarnation was last executed, and thus ready for validation, + // return version and guard for validation task, otherwise None. + self.is_executed(idx_to_validate) + .map(|incarnation| ((idx_to_validate, incarnation), guard)) + } + + /// Grab an index to try and execute next (by fetch-and-incrementing execution_idx). + /// - If the index is out of bounds, return None (and invoke a check of whethre + /// all txns can be committed). + /// - If the transaction is ready for execution (ReadyToExecute state), attempt + /// to create the next incarnation (should happen exactly once), and if successful, + /// return the version to the caller together with a guard to be used for the + /// corresponding ExecutionTask. + /// - Otherwise, return None. + fn try_execute_next_version(&self) -> Option<(Version, Option, TaskGuard)> { + let idx_to_execute = self.execution_idx.load(Ordering::SeqCst); + + if idx_to_execute >= self.num_txns { + if !self.check_done() { + // Avoid pointlessly spinning, and give priority to other threads that may + // be working to finish the remaining tasks. + hint::spin_loop(); + } + return None; + } + + // Must create a guard before incrementing execution_idx. + let guard = TaskGuard::new(&self.num_active_tasks); + + let idx_to_execute = self.execution_idx.fetch_add(1, Ordering::SeqCst); + + // If successfully incarnated (changed status from ready to executing), + // return version and guard for execution task, otherwise None. + self.try_incarnate(idx_to_execute) + .map(|(incarnation, maybe_condvar)| { + ((idx_to_execute, incarnation), maybe_condvar, guard) + }) + } + + /// Put a transaction in a suspended state, with a condition variable that can be + /// used to wake it up after the dependency is resolved. + fn suspend(&self, txn_idx: TxnIndex, dep_condvar: DependencyCondvar) { + let mut status = self.txn_status[txn_idx].lock(); + + if let TransactionStatus::Executing(incarnation) = *status { + *status = TransactionStatus::Suspended(incarnation, dep_condvar); + } else { + unreachable!(); + } + } + + /// When a dependency is resolved, mark the transaction as ReadyToExecute with an + /// incremented incarnation number. + /// The caller must ensure that the transaction is in the Suspended state. + fn resume(&self, txn_idx: TxnIndex) { + // println!( + // "{:?} - Scheduler::resume | Entered, txn_id: {:?} ", + // thread::current().id(), + // txn_idx + // ); + + let mut status = self.txn_status[txn_idx].lock(); + if let TransactionStatus::Suspended(incarnation, dep_condvar) = &*status { + *status = TransactionStatus::ReadyToExecute(*incarnation, Some(dep_condvar.clone())); + } else { + unreachable!(); + } + // println!( + // "{:?} - Scheduler::resume | Exited, txn_id: {:?} ", + // thread::current().id(), + // txn_idx + // ); + } + + /// Set status of the transaction to Executed(incarnation). + fn set_executed_status(&self, txn_idx: TxnIndex, incarnation: Incarnation) { + let mut status = self.txn_status[txn_idx].lock(); + + // Only makes sense when the current status is 'Executing'. + debug_assert!(*status == TransactionStatus::Executing(incarnation)); + + *status = TransactionStatus::Executed(incarnation); + } + + /// After a successful abort, mark the transaction as ready for re-execution with + /// an incremented incarnation number. + fn set_aborted_status(&self, txn_idx: TxnIndex, incarnation: Incarnation) { + // println!( + // "{:?} - Scheduler::set_aborted_status | Entered, txn_id: {:?}, incarnation: {:?}", + // thread::current().id(), + // txn_idx, + // incarnation + // ); + + let mut status = self.txn_status[txn_idx].lock(); + + // Only makes sense when the current status is 'Aborting'. + debug_assert!(*status == TransactionStatus::Aborting(incarnation)); + + *status = TransactionStatus::ReadyToExecute(incarnation + 1, None); + + // println!( + // "{:?} - Scheduler::set_aborted_status | Exited, txn_id: {:?}, incarnation: {:?}", + // thread::current().id(), + // txn_idx, + // incarnation + // ); + } + + /// A lazy, check of whether the scheduler execution is completed. + /// Updates the 'done_marker' so other threads can know by calling done() function below. + /// + /// 1. After the STM execution has completed: + /// validation_idx >= num_txn, execution_idx >= num_txn, num_active_tasks == 0, + /// and decrease_cnt does not change - so it will be successfully detected. + /// 2. If done_marker is set, all of these must hold at the same time, implying completion. + /// Proof: O.w. one of the indices must decrease from when it is read to be >= num_txns + /// to when num_active_tasks is read to be 0, but decreasing thread is performing an active task, + /// so it must first perform the next instruction in 'decrease_validation_idx' or + /// 'decrease_execution_idx' functions, which is to increment the decrease_cnt++. + /// Final check will then detect a change in decrease_cnt and not allow a false positive. + fn check_done(&self) -> bool { + let observed_cnt = self.decrease_cnt.load(Ordering::SeqCst); + + let val_idx = self.validation_idx.load(Ordering::SeqCst); + let exec_idx = self.execution_idx.load(Ordering::SeqCst); + let num_tasks = self.num_active_tasks.load(Ordering::SeqCst); + if min(exec_idx, val_idx) < self.num_txns || num_tasks > 0 { + // There is work remaining. + return false; + } + + // Re-read and make sure decrease_cnt hasn't changed. + if observed_cnt == self.decrease_cnt.load(Ordering::SeqCst) { + self.done_marker.store(true, Ordering::Release); + true + } else { + false + } + } + + /// Checks whether the done marker is set. The marker can only be set by 'check_done'. + fn done(&self) -> bool { + self.done_marker.load(Ordering::Acquire) + } +} diff --git a/vm/transaction-benchmarks/src/main.rs b/vm/transaction-benchmarks/src/main.rs index a887b87924..4545618a9f 100644 --- a/vm/transaction-benchmarks/src/main.rs +++ b/vm/transaction-benchmarks/src/main.rs @@ -63,8 +63,8 @@ fn main() { // let acts = [1000]; //let txns = [10000, 50000, 100000]; - // let num_warmups = 2; - // let num_runs = 10; + let num_warmups = 2; + let num_runs = 10; println!( "num cpus = {}, run_seq: {}, run_seq: {}", From 2bfb4a6714c3ddedf9b7cdb09556db95eba890e3 Mon Sep 17 00:00:00 2001 From: welbon Date: Wed, 8 Nov 2023 19:13:32 +0800 Subject: [PATCH 64/89] [e2e-testsuite] cherry pick from branch tps_benchmark_e2e_testsuite --- Cargo.lock | 6 + vm/e2e-tests/src/account.rs | 48 +- .../src/account_universe/bad_transaction.rs | 2 +- vm/e2e-tests/src/executor.rs | 41 +- vm/e2e-tests/src/lib.rs | 2 +- vm/e2e-tests/src/utils.rs | 31 +- vm/e2e-tests/src/versioning.rs | 18 +- vm/e2e-testsuite/Cargo.toml | 7 +- vm/e2e-testsuite/src/tests/admin_script.rs | 21 +- vm/e2e-testsuite/src/tests/create_account.rs | 10 +- vm/e2e-testsuite/src/tests/data_store.rs | 6 +- .../src/tests/emergency_admin_script.rs | 34 +- vm/e2e-testsuite/src/tests/experimental.rs | 37 +- .../src/tests/failed_transaction_tests.rs | 172 +-- vm/e2e-testsuite/src/tests/fake_stdlib.rs | 545 ++++++++ vm/e2e-testsuite/src/tests/genesis.rs | 33 +- .../src/tests/genesis_initializations.rs | 4 +- vm/e2e-testsuite/src/tests/mint.rs | 31 +- vm/e2e-testsuite/src/tests/mod.rs | 4 +- .../src/tests/module_publishing.rs | 46 +- vm/e2e-testsuite/src/tests/multi_agent.rs | 235 ---- .../src/tests/on_chain_configs.rs | 44 +- .../src/tests/parallel_execution.rs | 22 +- vm/e2e-testsuite/src/tests/peer_to_peer.rs | 276 ++-- vm/e2e-testsuite/src/tests/preburn_queue.rs | 26 +- vm/e2e-testsuite/src/tests/rotate_key.rs | 148 +-- .../src/tests/script_functions.rs | 18 +- vm/e2e-testsuite/src/tests/scripts.rs | 68 +- .../src/tests/transaction_builder.rs | 364 +++--- .../src/tests/transaction_fees.rs | 37 +- .../src/tests/transaction_fuzzer.rs | 4 +- .../src/tests/validator_set_management.rs | 45 +- vm/e2e-testsuite/src/tests/vasps.rs | 196 --- vm/e2e-testsuite/src/tests/verify_txn.rs | 1135 +++++++++-------- vm/e2e-testsuite/src/tests/write_set.rs | 418 +++--- .../src/tests/writeset_builder.rs | 174 ++- vm/transaction-builder/src/lib.rs | 45 +- .../src/account_config/constants/addresses.rs | 9 + vm/types/src/lib.rs | 3 + .../on_chain_config/genesis_gas_schedule.rs | 4 +- vm/types/src/test_helpers/empty_script.mv | Bin 0 -> 18 bytes vm/types/src/test_helpers/mod.rs | 4 + .../test_helpers/transaction_test_helpers.rs | 252 ++++ vm/vm-runtime/src/starcoin_vm.rs | 2 +- 44 files changed, 2669 insertions(+), 1958 deletions(-) create mode 100644 vm/e2e-testsuite/src/tests/fake_stdlib.rs delete mode 100644 vm/e2e-testsuite/src/tests/multi_agent.rs delete mode 100644 vm/e2e-testsuite/src/tests/vasps.rs create mode 100644 vm/types/src/test_helpers/empty_script.mv create mode 100644 vm/types/src/test_helpers/mod.rs create mode 100644 vm/types/src/test_helpers/transaction_test_helpers.rs diff --git a/Cargo.lock b/Cargo.lock index ddc01775d7..7d5a11416d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9869,6 +9869,7 @@ name = "starcoin-language-e2e-testsuite" version = "1.13.7" dependencies = [ "bcs", + "bcs-ext", "hex", "move-binary-format", "move-bytecode-verifier", @@ -9878,14 +9879,19 @@ dependencies = [ "move-vm-types", "proptest", "read-write-set", + "serde 1.0.152", "serde_json", + "starcoin-config", "starcoin-crypto", + "starcoin-gas", + "starcoin-gas-algebra-ext", "starcoin-language-e2e-tests", "starcoin-logger", "starcoin-transaction-builder", "starcoin-types", "starcoin-vm-runtime", "starcoin-vm-types", + "test-helper", ] [[package]] diff --git a/vm/e2e-tests/src/account.rs b/vm/e2e-tests/src/account.rs index 5b4bbec6ac..09ac4c6c6d 100644 --- a/vm/e2e-tests/src/account.rs +++ b/vm/e2e-tests/src/account.rs @@ -19,9 +19,12 @@ use starcoin_vm_types::language_storage::StructTag; use starcoin_vm_types::move_resource::MoveResource; use starcoin_vm_types::state_store::state_key::StateKey; use starcoin_vm_types::token::token_code::TokenCode; -use starcoin_vm_types::transaction::authenticator::{AccountPrivateKey, AccountPublicKey}; +use starcoin_vm_types::transaction::authenticator::{ + AccountPrivateKey, AccountPublicKey, AuthenticationKey, +}; use starcoin_vm_types::transaction::{ - RawUserTransaction, Script, ScriptFunction, SignedUserTransaction, TransactionPayload, + Module, Package, RawUserTransaction, Script, ScriptFunction, SignedUserTransaction, + TransactionPayload, }; use starcoin_vm_types::value::{MoveStructLayout, MoveTypeLayout}; use starcoin_vm_types::values::{Struct, Value}; @@ -142,6 +145,26 @@ impl Account { &self.addr } + pub fn new_testing_dd() -> Self { + Self::new_genesis_account( + AccountAddress::from_hex_literal("0xDD") + .expect("Parsing valid hex literal should always succeed"), + ) + } + + pub fn new_blessed_tc() -> Self { + Self::new_genesis_account( + AccountAddress::from_hex_literal("0xB1E55ED") + .expect("Parsing valid hex literal should always succeed"), + ) + } + + pub fn auth_key_prefix(&self) -> Vec { + AuthenticationKey::ed25519(&self.public_key()) + .prefix() + .to_vec() + } + /// Returns the AccessPath that describes the Account balance resource instance. /// /// Use this to retrieve or publish the Account balance blob. @@ -231,6 +254,7 @@ pub struct TransactionBuilder { pub program: Option, pub max_gas_amount: Option, pub gas_unit_price: Option, + pub gas_currency_code: Option, pub chain_id: Option, pub ttl: Option, } @@ -246,6 +270,7 @@ impl TransactionBuilder { gas_unit_price: None, chain_id: None, ttl: None, + gas_currency_code: None, } } @@ -279,10 +304,12 @@ impl TransactionBuilder { self } - // pub fn module(mut self, m: Module) -> Self { - // self.program = Some(TransactionPayload::ModuleBundle(ModuleBundle::from(m))); - // self - // } + pub fn module(mut self, m: Module) -> Self { + self.program = Some(TransactionPayload::Package( + Package::new_with_module(m).unwrap(), + )); + self + } // TODO(BobOng): e2e-test // pub fn write_set(mut self, w: WriteSetPayload) -> Self { @@ -300,13 +327,18 @@ impl TransactionBuilder { self } + pub fn gas_currency_code(mut self, gas_currency_code: &str) -> Self { + self.gas_currency_code = Some(gas_currency_code.to_string()); + self + } + pub fn ttl(mut self, ttl: u64) -> Self { self.ttl = Some(ttl); self } pub fn raw(self) -> RawUserTransaction { - RawUserTransaction::new_with_default_gas_token( + RawUserTransaction::new( *self.sender.address(), self.sequence_number.expect("sequence number not set"), self.program.expect("transaction payload not set"), @@ -314,6 +346,8 @@ impl TransactionBuilder { self.gas_unit_price.unwrap_or(0), self.ttl.unwrap_or(DEFAULT_EXPIRATION_TIME), ChainId::test(), + self.gas_currency_code + .unwrap_or_else(|| STC_TOKEN_CODE_STR.to_string()), ) } diff --git a/vm/e2e-tests/src/account_universe/bad_transaction.rs b/vm/e2e-tests/src/account_universe/bad_transaction.rs index c8671adabd..dc30012d43 100644 --- a/vm/e2e-tests/src/account_universe/bad_transaction.rs +++ b/vm/e2e-tests/src/account_universe/bad_transaction.rs @@ -124,7 +124,7 @@ pub struct InvalidAuthkeyGen { #[proptest( strategy = "starcoin_crypto::test_utils::uniform_keypair_strategy_with_perturbation(1)" )] - new_keypair: KeyPair, + new_keypair0: KeyPair, } impl AUTransactionGen for InvalidAuthkeyGen { diff --git a/vm/e2e-tests/src/executor.rs b/vm/e2e-tests/src/executor.rs index f4e07db1ea..744770107a 100644 --- a/vm/e2e-tests/src/executor.rs +++ b/vm/e2e-tests/src/executor.rs @@ -40,7 +40,11 @@ use starcoin_vm_types::{ }; use crate::data_store::FakeDataStore; +use anyhow::Result as AnyhowResult; use starcoin_statedb::ChainStateWriter; +use starcoin_vm_types::state_store::table::{TableHandle, TableInfo}; +use starcoin_vm_types::transaction::TransactionInfo; +use std::collections::BTreeMap; use std::fs::OpenOptions; use std::io::Write; use std::path::{Path, PathBuf}; @@ -113,33 +117,40 @@ impl FakeExecutor { Self::no_genesis() } - pub fn from_test_genesis() -> Self { + pub fn from_test_genesis_with_info( + ) -> (Self, (BTreeMap, TransactionInfo)) { //let (state_db, net) = prepare_genesis(); let fake_executor = Self::no_genesis(); let net = ChainNetwork::new_test(); let genesis_txn = Genesis::build_genesis_transaction(&net).unwrap(); - let useless = + let result = Genesis::execute_genesis_txn(fake_executor.get_state_view(), genesis_txn).unwrap(); + (fake_executor, result) + } + + pub fn from_test_genesis() -> Self { + //let (state_db, net) = prepare_genesis(); + let (executor, useless) = Self::from_test_genesis_with_info(); drop(useless); - fake_executor + executor } /// Creates an executor from the genesis file GENESIS_FILE_LOCATION with script/module /// publishing options given by `publishing_options`. These can only be either `Open` or /// `CustomScript`. - pub fn from_genesis_with_options(_publishing_options: VMConfig) -> Self { - // if !publishing_options.is_open_script() { - // panic!("Allowlisted transactions are not supported as a publishing option") - // } + //pub fn from_genesis_with_options(_publishing_options: VMPublishingOption) -> Self { + // if !publishing_options.is_open_script() { + // panic!("Allowlisted transactions are not supported as a publishing option") + // } - // Self::custom_genesis( - // cached_framework_packages::module_blobs(), - // None, - // publishing_options, - // ) - // TODO(BobOng): e2e-test - Self::no_genesis() - } + // Self::custom_genesis( + // cached_framework_packages::module_blobs(), + // None, + // publishing_options, + // ) + // TODO(BobOng): e2e-test + // Self::no_genesis() + //} /// Creates an executor in which no genesis state has been applied yet. pub fn no_genesis() -> Self { diff --git a/vm/e2e-tests/src/lib.rs b/vm/e2e-tests/src/lib.rs index 91c7d29bd7..8099dbbbea 100644 --- a/vm/e2e-tests/src/lib.rs +++ b/vm/e2e-tests/src/lib.rs @@ -45,7 +45,7 @@ pub fn transaction_status_eq(t1: &TransactionStatus, t2: &TransactionStatus) -> #[macro_export] macro_rules! assert_prologue_parity { ($e1:expr, $e2:expr, $e3:expr) => { - assert_eq!($e1.unwrap(), $e3); + assert_eq!($e1, $e3); assert!(transaction_status_eq($e2, &TransactionStatus::Discard($e3))); }; } diff --git a/vm/e2e-tests/src/utils.rs b/vm/e2e-tests/src/utils.rs index a1ce86fdd2..64b036dab9 100644 --- a/vm/e2e-tests/src/utils.rs +++ b/vm/e2e-tests/src/utils.rs @@ -31,8 +31,27 @@ pub fn close_module_publishing( *dr_seqno = dr_seqno.checked_add(1).unwrap(); } -pub fn start_with_released_df() -> (FakeExecutor, Account) { - // TODO(BobOng): e2e-test +pub fn start_with_released_df() -> (FakeExecutor, Account, Account, Account) { + let executor = FakeExecutor::from_test_genesis(); + + let dd_account = Account::new_testing_dd(); + let dr_account = Account::new_starcoin_root(); + let tc_account = Account::new_blessed_tc(); + + // dd_account.rotate_key( + // bcs::from_bytes(executor::RELEASE_1_1_GENESIS_PRIVKEY).unwrap(), + // bcs::from_bytes(executor::RELEASE_1_1_GENESIS_PUBKEY).unwrap(), + // ); + // dr_account.rotate_key( + // bcs::from_bytes(executor::RELEASE_1_1_GENESIS_PRIVKEY).unwrap(), + // bcs::from_bytes(executor::RELEASE_1_1_GENESIS_PUBKEY).unwrap(), + // ); + // tc_account.rotate_key( + // bcs::from_bytes(executor::RELEASE_1_1_GENESIS_PRIVKEY).unwrap(), + // bcs::from_bytes(executor::RELEASE_1_1_GENESIS_PUBKEY).unwrap(), + // ); + (executor, dr_account, tc_account, dd_account) + // let executor = FakeExecutor::from_fresh_genesis(); // let mut dr_account = Account::new_starcoin_root(); // @@ -40,10 +59,10 @@ pub fn start_with_released_df() -> (FakeExecutor, Account) { // dr_account.rotate_key(private_key, public_key); // // (executor, dr_account) - ( - FakeExecutor::from_fresh_genesis(), - Account::new_starcoin_root(), - ) + // ( + // FakeExecutor::from_fresh_genesis(), + // Account::new_starcoin_root(), + // ) } pub fn upgrade_df( diff --git a/vm/e2e-tests/src/versioning.rs b/vm/e2e-tests/src/versioning.rs index 2677e94029..c6b2a7e57b 100644 --- a/vm/e2e-tests/src/versioning.rs +++ b/vm/e2e-tests/src/versioning.rs @@ -15,20 +15,30 @@ pub const CURRENT_RELEASE_VERSIONS: std::ops::RangeInclusive = 1..=12; pub struct VersionedTestEnv { pub executor: FakeExecutor, pub dr_account: Account, + pub tc_account: Account, + pub dd_account: Account, pub dr_sequence_number: u64, + pub tc_sequence_number: u64, + pub dd_sequence_number: u64, pub version_number: u64, } impl VersionedTestEnv { // At each release, this function will need to be updated to handle the release logic pub fn new(version_number: u64) -> Option { - let (executor, dr_account) = utils::start_with_released_df(); + let (executor, dr_account, tc_account, dd_account) = utils::start_with_released_df(); let dr_sequence_number = 0; + let tc_sequence_number = 0; + let dd_sequence_number = 0; Some(Self { executor, dr_account, + tc_account, + dd_account, dr_sequence_number, + tc_sequence_number, + dd_sequence_number, version_number, }) } @@ -66,10 +76,10 @@ pub fn run_with_versions( #[macro_export] macro_rules! test_with_different_versions { ($versions:expr, $expr:expr) => { - language_e2e_tests::versioning::run_with_versions( - language_e2e_tests::current_function_name!(), + starcoin_language_e2e_tests::versioning::run_with_versions( + starcoin_language_e2e_tests::current_function_name!(), $versions, - language_e2e_tests::versioning::VersionedTestEnv::new, + starcoin_language_e2e_tests::versioning::VersionedTestEnv::new, $expr, ) }; diff --git a/vm/e2e-testsuite/Cargo.toml b/vm/e2e-testsuite/Cargo.toml index 2ee7a8ce74..29e6c04078 100644 --- a/vm/e2e-testsuite/Cargo.toml +++ b/vm/e2e-testsuite/Cargo.toml @@ -33,7 +33,12 @@ starcoin-vm-runtime = { workspace = true } starcoin-vm-types = { workspace = true } starcoin-types = { workspace = true } starcoin-crypto = { workspace = true } - +starcoin-gas-algebra-ext = { workspace = true } +starcoin-gas = { workspace = true } +starcoin-config = { workspace = true } +test-helper = { workspace = true } +bcs-ext = { workspace = true } +serde = { workspace = true } #diem-keygen = { path = "../diem-keygen" } #starcoin-vm = { path = "../starcoin-vm" } diff --git a/vm/e2e-testsuite/src/tests/admin_script.rs b/vm/e2e-testsuite/src/tests/admin_script.rs index d49afd8e9a..0a940e11e0 100644 --- a/vm/e2e-testsuite/src/tests/admin_script.rs +++ b/vm/e2e-testsuite/src/tests/admin_script.rs @@ -1,18 +1,19 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use move_core_types::transaction_argument::TransactionArgument; use move_core_types::vm_status::StatusCode; use move_ir_compiler::Compiler; -use starcoin_crypto::ed25519::Ed25519PrivateKey; -use starcoin_crypto::{PrivateKey, Uniform}; -use starcoin_language_e2e_tests::account::Account; -use starcoin_language_e2e_tests::{current_function_name, executor::FakeExecutor}; +use starcoin_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, Uniform}; + +use starcoin_language_e2e_tests::{ + account::Account, current_function_name, executor::FakeExecutor, +}; use starcoin_transaction_builder::{stdlib_compiled_modules, StdLibOptions}; -use starcoin_vm_types::genesis_config::StdlibVersion::Latest; -use starcoin_vm_types::on_chain_config; -use starcoin_vm_types::transaction::authenticator::AuthenticationKey; -use starcoin_vm_types::transaction::Script; +use starcoin_vm_types::{ + genesis_config::StdlibVersion::Latest, + on_chain_config, + transaction::{authenticator::AuthenticationKey, Script}, +}; #[test] fn admin_script_rotate_key_single_signer_no_epoch() { @@ -85,7 +86,7 @@ fn admin_script_rotate_key_single_signer_new_epoch() { let script_body = { let code = r#" import 0x1.Account; -import 0x1.DiemConfig; +import 0x1.Config; main(dr_account: signer, account: signer, auth_key_prefix: vector) { let rotate_cap: Account.KeyRotationCapability; diff --git a/vm/e2e-testsuite/src/tests/create_account.rs b/vm/e2e-testsuite/src/tests/create_account.rs index c39b10be5a..4bff47b46a 100644 --- a/vm/e2e-testsuite/src/tests/create_account.rs +++ b/vm/e2e-testsuite/src/tests/create_account.rs @@ -2,10 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 use move_core_types::vm_status::KeptVMStatus; -use starcoin_language_e2e_tests::account::Account; -use starcoin_language_e2e_tests::common_transactions::create_account_txn; -use starcoin_language_e2e_tests::current_function_name; -use starcoin_language_e2e_tests::executor::FakeExecutor; +use starcoin_language_e2e_tests::{ + account::Account, common_transactions::create_account_txn, current_function_name, + executor::FakeExecutor, +}; use starcoin_vm_types::transaction::TransactionStatus; #[test] @@ -37,6 +37,6 @@ fn create_account() { let updated_receiver_balance = executor .read_balance_resource(&new_account) .expect("receiver balance must exist"); - assert_eq!(initial_amount, updated_receiver_balance.coin()); + assert_eq!(initial_amount, updated_receiver_balance.token() as u64); assert_eq!(1, updated_sender.sequence_number()); } diff --git a/vm/e2e-testsuite/src/tests/data_store.rs b/vm/e2e-testsuite/src/tests/data_store.rs index 61d18bbc5c..38c1bd8513 100644 --- a/vm/e2e-testsuite/src/tests/data_store.rs +++ b/vm/e2e-testsuite/src/tests/data_store.rs @@ -9,9 +9,9 @@ use starcoin_language_e2e_tests::{ account::AccountData, compile::compile_script, current_function_name, executor::FakeExecutor, }; use starcoin_transaction_builder::{stdlib_compiled_modules, StdLibOptions}; -use starcoin_vm_types::genesis_config::StdlibVersion::Latest; -use starcoin_vm_types::transaction::{ - Module, SignedUserTransaction, Transaction, TransactionStatus, +use starcoin_vm_types::{ + genesis_config::StdlibVersion::Latest, + transaction::{Module, SignedUserTransaction, Transaction, TransactionStatus}, }; #[test] diff --git a/vm/e2e-testsuite/src/tests/emergency_admin_script.rs b/vm/e2e-testsuite/src/tests/emergency_admin_script.rs index d4cad22d60..b6c1f28b2d 100644 --- a/vm/e2e-testsuite/src/tests/emergency_admin_script.rs +++ b/vm/e2e-testsuite/src/tests/emergency_admin_script.rs @@ -1,7 +1,27 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use starcoin_language_e2e_tests::test_with_different_versions; +use starcoin_language_e2e_tests::{ + common_transactions::peer_to_peer_txn, test_with_different_versions, + versioning::CURRENT_RELEASE_VERSIONS, +}; +use starcoin_vm_types::{ + on_chain_config::new_epoch_event_key, + transaction::Transaction, + value::{serialize_values, MoveValue}, + vm_status::{KeptVMStatus, StatusCode}, +}; + +use serde_json::json; +use starcoin_types::transaction::TransactionStatus; + +use crate::tests::fake_stdlib::{ + encode_add_validator_and_reconfigure_script, encode_create_validator_account_script, + encode_create_validator_operator_account_script, encode_custom_script, + encode_halt_network_payload, encode_register_validator_config_script, + encode_remove_validators_payload, encode_rotate_authentication_key_script, + encode_set_validator_operator_script, +}; #[test] fn validator_batch_remove() { @@ -143,15 +163,15 @@ fn validator_batch_remove() { .sign(), ); - let txn1 = Transaction::GenesisTransaction(encode_remove_validators_payload(vec![ + let txn1 = Transaction::UserTransaction(encode_remove_validators_payload(vec![ *validator_account_0.address(), *validator_account_1.address(), ])); - let txn2 = Transaction::GenesisTransaction(encode_custom_script( + let txn2 = Transaction::UserTransaction(encode_custom_script( "remove_validators.move", &json!({ "addresses": [validator_account_0.address().to_string(), validator_account_1.address().to_string()]}), - Some(diem_root_address()), + Some(diem_root_account.address().clone()), )); assert_eq!(txn1, txn2); @@ -204,7 +224,7 @@ fn validator_batch_remove() { fn halt_network() { // This can only run on versions >= 2 since // `DiemTransactionPublishingOption::halt_all_transactions` is not available in version 1. - test_with_different_versions! {2..=DIEM_MAX_KNOWN_VERSION.major, |test_env| { + test_with_different_versions! {2..=12, |test_env| { let mut executor = test_env.executor; let diem_root_account = test_env.dr_account; let sender = executor.create_raw_account_data(1_000_000, 10); @@ -214,7 +234,7 @@ fn halt_network() { executor.new_block(); let output = executor - .execute_transaction_block(vec![Transaction::GenesisTransaction( + .execute_transaction_block(vec![Transaction::UserTransaction( encode_halt_network_payload(), )]) .unwrap() @@ -227,7 +247,7 @@ fn halt_network() { executor.apply_write_set(output.write_set()); - let txn = peer_to_peer_txn(sender.account(), receiver.account(), 10, 1); + let txn = peer_to_peer_txn(sender.account(), receiver.account(), 0, 10); // Regular transactions like p2p are no longer allowed. let output = executor.execute_transaction(txn); assert_eq!( diff --git a/vm/e2e-testsuite/src/tests/experimental.rs b/vm/e2e-testsuite/src/tests/experimental.rs index b960829ddc..8888e14780 100644 --- a/vm/e2e-testsuite/src/tests/experimental.rs +++ b/vm/e2e-testsuite/src/tests/experimental.rs @@ -2,30 +2,38 @@ // SPDX-License-Identifier: Apache-2.0 use move_core_types::vm_status::StatusCode; +use starcoin_config::ChainNetwork; use starcoin_language_e2e_tests::account::Account; use starcoin_language_e2e_tests::current_function_name; use starcoin_language_e2e_tests::executor::FakeExecutor; use starcoin_transaction_builder::encode_create_account_script_function; +use starcoin_vm_types::account_config::stc_type_tag; +use starcoin_vm_types::transaction::authenticator::AuthenticationKey; // Make sure we can start the experimental genesis #[test] fn experimental_genesis_runs() { - FakeExecutor::from_experimental_genesis(); + //FakeExecutor::from_experimental_genesis(); + FakeExecutor::from_test_genesis(); } // Make sure that we can execute transactions with the experimental genesis #[test] fn experimental_genesis_execute_txn_successful() { - let mut executor = FakeExecutor::from_experimental_genesis(); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); + let net = ChainNetwork::new_test(); let new_account = executor.create_raw_account(); let new_new_account = executor.create_raw_account(); let dr_account = Account::new_starcoin_root(); let txn = dr_account .transaction() .script_function(encode_create_account_script_function( - *new_account.address(), - new_account.auth_key_prefix(), + net.stdlib_version(), + stc_type_tag(), + &new_account.address(), + AuthenticationKey::try_from(new_account.auth_key_prefix()).unwrap(), + 0, )) .sequence_number(0) .sign(); @@ -34,9 +42,12 @@ fn experimental_genesis_execute_txn_successful() { // Other accounts can create accounts, no role checks let txn = new_account .transaction() - .payload(encode_create_account_script_function( - *new_new_account.address(), - new_new_account.auth_key_prefix(), + .script_function(encode_create_account_script_function( + net.stdlib_version(), + stc_type_tag(), + &new_account.address(), + AuthenticationKey::try_from(new_account.auth_key_prefix()).unwrap(), + 0, )) .sequence_number(0) .sign(); @@ -46,14 +57,18 @@ fn experimental_genesis_execute_txn_successful() { // Make sure that we can handle prologue errors from the non-DPN account module #[test] fn experimental_genesis_execute_txn_non_existent_sender() { - let mut executor = FakeExecutor::from_experimental_genesis(); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); + let net = ChainNetwork::new_test(); let new_account = executor.create_raw_account(); let txn = new_account .transaction() - .payload(encode_create_account_script_function( - *new_account.address(), - new_account.auth_key_prefix(), + .script_function(encode_create_account_script_function( + net.stdlib_version(), + stc_type_tag(), + &new_account.address(), + AuthenticationKey::try_from(new_account.auth_key_prefix()).unwrap(), + 0, )) .sequence_number(0) .sign(); diff --git a/vm/e2e-testsuite/src/tests/failed_transaction_tests.rs b/vm/e2e-testsuite/src/tests/failed_transaction_tests.rs index 204fa703d5..5856ba2706 100644 --- a/vm/e2e-testsuite/src/tests/failed_transaction_tests.rs +++ b/vm/e2e-testsuite/src/tests/failed_transaction_tests.rs @@ -1,90 +1,118 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use starcoin_language_e2e_tests::test_with_different_versions; +use move_core_types::gas_algebra::NumBytes; +use move_core_types::vm_status::{KeptVMStatus, StatusCode, VMStatus}; + +use starcoin_language_e2e_tests::common_transactions::peer_to_peer_txn; +use starcoin_language_e2e_tests::executor::FakeExecutor; + +use starcoin_vm_runtime::{ + data_cache::{AsMoveResolver, StateViewCache}, + starcoin_vm::StarcoinVM, +}; + +use starcoin_vm_types::{ + account_config::G_STC_TOKEN_CODE, transaction_metadata::TransactionMetadata, + transaction_metadata::TransactionPayloadMetadata, +}; + +use starcoin_gas::{StarcoinGasMeter, StarcoinGasParameters}; +use starcoin_gas_algebra_ext::{FeePerGasUnit, Gas, InitialGasSchedule}; +use starcoin_vm_types::genesis_config::ChainId; #[test] fn failed_transaction_cleanup_test() { - test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { - let mut executor = test_env.executor; - let sender = executor.create_raw_account_data(1_000_000, 10); - executor.add_account_data(&sender); + //test_with_different_versions!{CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = FakeExecutor::from_test_genesis(); //test_env.executor; + let sender = executor.create_raw_account_data(1_000_000, 10); + executor.add_account_data(&sender); - let log_context = AdapterLogSchema::new(executor.get_state_view().id(), 0); - let diem_vm = DiemVM::new(executor.get_state_view()); - let data_cache = StateViewCache::new(executor.get_state_view()); + //let log_context = AdapterLogSchema::new(executor.get_state_view().id(), 0); + let vm = StarcoinVM::new(None); + let data_cache = StateViewCache::new(executor.get_state_view()); - let txn_data = TransactionMetadata { - sender: *sender.address(), - max_gas_amount: GasUnits::new(100_000), - gas_unit_price: GasPrice::new(0), - sequence_number: 10, - ..Default::default() - }; + let txn_data = TransactionMetadata { + sender: *sender.address(), + max_gas_amount: Gas::new(100_000), + gas_unit_price: FeePerGasUnit::new(0), + gas_token_code: G_STC_TOKEN_CODE.clone(), + transaction_size: NumBytes::new(0), + expiration_timestamp_secs: 0, + sequence_number: 10, + payload: TransactionPayloadMetadata::ScriptFunction, + authentication_key_preimage: vec![], + chain_id: ChainId::test(), + }; - let gas_schedule = zero_cost_schedule(); - let mut gas_status = GasStatus::new(&gas_schedule, GasUnits::new(10_000)); + // let gas_schedule = zero_cost_schedule(); + // let mut gas_status = GasStatus::new(&gas_schedule, GasUnits::new(10_000)); + let mut gas_meter = make_test_starcoin_gas_parameter(); + // TYPE_MISMATCH should be kept and charged. + let (_, out1) = vm.failed_transaction_cleanup( + VMStatus::Error(StatusCode::TYPE_MISMATCH), + &mut gas_meter, + &txn_data, + &data_cache.as_move_resolver(), + ); - // TYPE_MISMATCH should be kept and charged. - let out1 = diem_vm.failed_transaction_cleanup( - VMStatus::Error(StatusCode::TYPE_MISMATCH), - &mut gas_status, - &txn_data, - &data_cache, - &account::xus_currency_code(), - &log_context, - ); - assert!(!out1.write_set().is_empty()); - assert_eq!(out1.gas_used(), 90_000); - assert!(!out1.status().is_discarded()); - assert_eq!( - out1.status().status(), - // StatusCode::TYPE_MISMATCH - Ok(KeptVMStatus::MiscellaneousError) - ); + assert!(!out1.write_set().is_empty()); + assert_eq!(out1.gas_used(), 90_000); + assert!(!out1.status().is_discarded()); + assert_eq!( + out1.status().status(), + // StatusCode::TYPE_MISMATCH + Ok(KeptVMStatus::MiscellaneousError) + ); - // Invariant violations should be discarded and not charged. - let out2 = diem_vm.failed_transaction_cleanup( - VMStatus::Error(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR), - &mut gas_status, - &txn_data, - &data_cache, - &account::xus_currency_code(), - &log_context, - ); - assert!(out2.write_set().is_empty()); - assert!(out2.gas_used() == 0); - assert!(out2.status().is_discarded()); - assert_eq!( - out2.status().status(), - Err(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) - ); - } - } + // Invariant violations should be discarded and not charged. + let (_, out2) = vm.failed_transaction_cleanup( + VMStatus::Error(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR), + &mut gas_meter, + &txn_data, + &data_cache.as_move_resolver(), + ); + assert!(out2.write_set().is_empty()); + assert!(out2.gas_used() == 0); + assert!(out2.status().is_discarded()); + assert_eq!( + out2.status().status(), + Err(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) + ); + //} + //} } #[test] fn non_existent_sender() { - test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { - let mut executor = test_env.executor; - let sequence_number = 0; - let sender = executor.create_raw_account(); - let receiver = executor.create_raw_account_data(100_000, sequence_number); - executor.add_account_data(&receiver); + //test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + let mut executor = FakeExecutor::from_test_genesis(); + let sequence_number = 0; + let sender = executor.create_raw_account(); + let receiver = executor.create_raw_account_data(100_000, sequence_number); + executor.add_account_data(&receiver); + + let transfer_amount = 10; + let txn = peer_to_peer_txn( + &sender, + receiver.account(), + sequence_number, + transfer_amount, + ); - let transfer_amount = 10; - let txn = peer_to_peer_txn( - &sender, - receiver.account(), - sequence_number, - transfer_amount, - ); + let output = &executor.execute_transaction(txn); + assert_eq!( + output.status().status(), + Err(StatusCode::SENDING_ACCOUNT_DOES_NOT_EXIST), + ); +} +//} +//} - let output = &executor.execute_transaction(txn); - assert_eq!( - output.status().status(), - Err(StatusCode::SENDING_ACCOUNT_DOES_NOT_EXIST), - ); - } - } +fn make_test_starcoin_gas_parameter() -> StarcoinGasMeter { + let gas_params = StarcoinGasParameters::initial(); + let balance = gas_params.txn.maximum_number_of_gas_units.clone(); + let mut gas_meter = StarcoinGasMeter::new(gas_params, balance); + gas_meter.set_metering(false); + gas_meter } diff --git a/vm/e2e-testsuite/src/tests/fake_stdlib.rs b/vm/e2e-testsuite/src/tests/fake_stdlib.rs new file mode 100644 index 0000000000..6d0e9b34e4 --- /dev/null +++ b/vm/e2e-testsuite/src/tests/fake_stdlib.rs @@ -0,0 +1,545 @@ +// Copyright (c) The Starcoin Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use bcs_ext::Sample; +use move_core_types::{account_address::AccountAddress, language_storage::TypeTag}; +use serde::Serialize; +use starcoin_vm_types::transaction::{Script, SignedUserTransaction, TransactionPayload}; + +pub fn encode_create_validator_account_script( + _sliding_nonce: u64, + _new_account_address: AccountAddress, + _auth_key_prefix: Vec, + _human_name: Vec, +) -> Script { + // Script::new( + // CREATE_VALIDATOR_ACCOUNT_CODE.to_vec(), + // vec![], + // vec![ + // TransactionArgument::U64(sliding_nonce), + // TransactionArgument::Address(new_account_address), + // TransactionArgument::U8Vector(auth_key_prefix), + // TransactionArgument::U8Vector(human_name), + // ], + // ) + Script::sample() +} + +pub fn encode_create_validator_operator_account_script( + _sliding_nonce: u64, + _new_account_address: AccountAddress, + _auth_key_prefix: Vec, + _human_name: Vec, +) -> Script { + // Script::new( + // CREATE_VALIDATOR_OPERATOR_ACCOUNT_CODE.to_vec(), + // vec![], + // vec![ + // TransactionArgument::U64(sliding_nonce), + // TransactionArgument::Address(new_account_address), + // TransactionArgument::U8Vector(auth_key_prefix), + // TransactionArgument::U8Vector(human_name), + // ], + // ) + Script::sample() +} + +pub fn encode_set_validator_operator_script( + _operator_name: Vec, + _operator_account: AccountAddress, +) -> Script { + // Script::new( + // CREATE_VALIDATOR_OPERATOR_ACCOUNT_CODE.to_vec(), + // vec![], + // vec![ + // TransactionArgument::U64(sliding_nonce), + // TransactionArgument::Address(new_account_address), + // TransactionArgument::U8Vector(auth_key_prefix), + // TransactionArgument::U8Vector(human_name), + // ], + // ) + Script::sample() +} + +pub fn encode_register_validator_config_script( + _validator_account: AccountAddress, + _consensus_pubkey: Vec, + _validator_network_addresses: Vec, + _fullnode_network_addresses: Vec, +) -> Script { + // Script::new( + // CREATE_VALIDATOR_OPERATOR_ACCOUNT_CODE.to_vec(), + // vec![], + // vec![ + // TransactionArgument::U64(sliding_nonce), + // TransactionArgument::Address(new_account_address), + // TransactionArgument::U8Vector(auth_key_prefix), + // TransactionArgument::U8Vector(human_name), + // ], + // ) + Script::sample() +} + +pub fn encode_add_validator_and_reconfigure_script( + _sliding_nonce: u64, + _validator_name: Vec, + _validator_address: AccountAddress, +) -> Script { + // Script::new( + // CREATE_VALIDATOR_OPERATOR_ACCOUNT_CODE.to_vec(), + // vec![], + // vec![ + // TransactionArgument::U64(sliding_nonce), + // TransactionArgument::Address(new_account_address), + // TransactionArgument::U8Vector(auth_key_prefix), + // TransactionArgument::U8Vector(human_name), + // ], + // ) + Script::sample() +} + +pub fn encode_preburn_script(_token: TypeTag, _amount: u64) -> Script { + // Script::new( + // CREATE_VALIDATOR_OPERATOR_ACCOUNT_CODE.to_vec(), + // vec![], + // vec![ + // TransactionArgument::U64(sliding_nonce), + // TransactionArgument::Address(new_account_address), + // TransactionArgument::U8Vector(auth_key_prefix), + // TransactionArgument::U8Vector(human_name), + // ], + // ) + Script::sample() +} + +pub fn encode_burn_script( + _token: TypeTag, + _sliding_nonce: u64, + _preburn_address: AccountAddress, +) -> Script { + // Script::new( + // CREATE_VALIDATOR_OPERATOR_ACCOUNT_CODE.to_vec(), + // vec![], + // vec![ + // TransactionArgument::U64(sliding_nonce), + // TransactionArgument::Address(new_account_address), + // TransactionArgument::U8Vector(auth_key_prefix), + // TransactionArgument::U8Vector(human_name), + // ], + // ) + Script::sample() +} + +pub fn encode_cancel_burn_script(_token: TypeTag, _preburn_address: AccountAddress) -> Script { + // Script::new( + // CREATE_VALIDATOR_OPERATOR_ACCOUNT_CODE.to_vec(), + // vec![], + // vec![ + // TransactionArgument::U64(sliding_nonce), + // TransactionArgument::Address(new_account_address), + // TransactionArgument::U8Vector(auth_key_prefix), + // TransactionArgument::U8Vector(human_name), + // ], + // ) + Script::sample() +} + +pub fn encode_burn_with_amount_script_function( + _token: TypeTag, + _sliding_nonce: u64, + _preburn_address: AccountAddress, + _amount: u64, +) -> TransactionPayload { + // Script::new( + // CREATE_VALIDATOR_OPERATOR_ACCOUNT_CODE.to_vec(), + // vec![], + // vec![ + // TransactionArgument::U64(sliding_nonce), + // TransactionArgument::Address(new_account_address), + // TransactionArgument::U8Vector(auth_key_prefix), + // TransactionArgument::U8Vector(human_name), + // ], + // ) + TransactionPayload::Script(Script::sample()) +} + +pub fn encode_cancel_burn_with_amount_script_function( + _token: TypeTag, + _preburn_address: AccountAddress, + _amount: u64, +) -> TransactionPayload { + // Script::new( + // CREATE_VALIDATOR_OPERATOR_ACCOUNT_CODE.to_vec(), + // vec![], + // vec![ + // TransactionArgument::U64(sliding_nonce), + // TransactionArgument::Address(new_account_address), + // TransactionArgument::U8Vector(auth_key_prefix), + // TransactionArgument::U8Vector(human_name), + // ], + // ) + TransactionPayload::Script(Script::sample()) +} + +pub fn encode_rotate_authentication_key_with_nonce_admin_script( + _sliding_nonce: u64, + _new_key: Vec, +) -> Script { + Script::sample() +} +// pub fn encode_rotate_authentication_key_with_nonce_admin_script_function( +// _sliding_nonce: u64, +// _new_key: Vec, +// ) -> TransactionPayload { +// TransactionPayload::Script(Script::sample()) +// } + +pub fn encode_create_parent_vasp_account_script( + _coin_type: TypeTag, + _sliding_nonce: u64, + _new_account_address: AccountAddress, + _auth_key_prefix: Vec, + _human_name: Vec, + _add_all_currencies: bool, +) -> Script { + // Script::new( + // CREATE_PARENT_VASP_ACCOUNT_CODE.to_vec(), + // vec![coin_type], + // vec![ + // TransactionArgument::U64(sliding_nonce), + // TransactionArgument::Address(new_account_address), + // TransactionArgument::U8Vector(auth_key_prefix), + // TransactionArgument::U8Vector(human_name), + // TransactionArgument::Bool(add_all_currencies), + // ], + // ) + Script::sample() +} + +pub fn encode_freeze_account_script( + sliding_nonce: u64, + to_freeze_account: AccountAddress, +) -> Script { + // Script::new( + // FREEZE_ACCOUNT_CODE.to_vec(), + // vec![], + // vec![ + // TransactionArgument::U64(sliding_nonce), + // TransactionArgument::Address(to_freeze_account), + // ], + // ) + Script::sample() +} + +pub fn encode_unfreeze_account_script( + _sliding_nonce: u64, + _to_unfreeze_account: AccountAddress, +) -> Script { + // Script::new( + // UNFREEZE_ACCOUNT_CODE.to_vec(), + // vec![], + // vec![ + // TransactionArgument::U64(sliding_nonce), + // TransactionArgument::Address(to_unfreeze_account), + // ], + // ) + Script::sample() +} + +pub fn encode_rotate_dual_attestation_info_script(_new_url: Vec, _new_key: Vec) -> Script { + // Script::new( + // ROTATE_DUAL_ATTESTATION_INFO_CODE.to_vec(), + // vec![], + // vec![ + // TransactionArgument::U8Vector(new_url), + // TransactionArgument::U8Vector(new_key), + // ], + // ) + Script::sample() +} + +pub fn encode_create_child_vasp_account_script( + _coin_type: TypeTag, + _child_address: AccountAddress, + _auth_key_prefix: Vec, + _add_all_currencies: bool, + _child_initial_balance: u64, +) -> Script { + // Script::new( + // CREATE_CHILD_VASP_ACCOUNT_CODE.to_vec(), + // vec![coin_type], + // vec![ + // TransactionArgument::Address(child_address), + // TransactionArgument::U8Vector(auth_key_prefix), + // TransactionArgument::Bool(add_all_currencies), + // TransactionArgument::U64(child_initial_balance), + // ], + // ) + Script::sample() +} + +pub fn encode_create_child_vasp_account_script_function( + _coin_type: TypeTag, + _child_address: AccountAddress, + _auth_key_prefix: Vec, + _add_all_currencies: bool, + _child_initial_balance: u64, +) -> TransactionPayload { + // TransactionPayload::ScriptFunction(ScriptFunction::new( + // ModuleId::new( + // AccountAddress::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]), + // ident_str!("AccountCreationScripts").to_owned(), + // ), + // ident_str!("create_child_vasp_account").to_owned(), + // vec![coin_type], + // vec![ + // bcs::to_bytes(&child_address).unwrap(), + // bcs::to_bytes(&auth_key_prefix).unwrap(), + // bcs::to_bytes(&add_all_currencies).unwrap(), + // bcs::to_bytes(&child_initial_balance).unwrap(), + // ], + // )) + TransactionPayload::Script(Script::sample()) +} + +pub fn encode_peer_to_peer_with_metadata_script( + _currency: TypeTag, + _payee: AccountAddress, + _amount: u64, + _metadata: Vec, + _metadata_signature: Vec, +) -> Script { + // Script::new( + // PEER_TO_PEER_WITH_METADATA_CODE.to_vec(), + // vec![currency], + // vec![ + // TransactionArgument::Address(payee), + // TransactionArgument::U64(amount), + // TransactionArgument::U8Vector(metadata), + // TransactionArgument::U8Vector(metadata_signature), + // ], + // ) + Script::sample() +} + +pub fn encode_create_designated_dealer_script( + _currency: TypeTag, + _sliding_nonce: u64, + _addr: AccountAddress, + _auth_key_prefix: Vec, + _human_name: Vec, + _add_all_currencies: bool, +) -> Script { + // Script::new( + // CREATE_DESIGNATED_DEALER_CODE.to_vec(), + // vec![currency], + // vec![ + // TransactionArgument::U64(sliding_nonce), + // TransactionArgument::Address(addr), + // TransactionArgument::U8Vector(auth_key_prefix), + // TransactionArgument::U8Vector(human_name), + // TransactionArgument::Bool(add_all_currencies), + // ], + // ) + Script::sample() +} + +pub fn encode_publish_shared_ed25519_public_key_script(_public_key: Vec) -> Script { + // Script::new( + // PUBLISH_SHARED_ED25519_PUBLIC_KEY_CODE.to_vec(), + // vec![], + // vec![TransactionArgument::U8Vector(public_key)], + // ) + Script::sample() +} + +pub fn encode_rotate_shared_ed25519_public_key_script(_public_key: Vec) -> Script { + // Script::new( + // ROTATE_SHARED_ED25519_PUBLIC_KEY_CODE.to_vec(), + // vec![], + // vec![TransactionArgument::U8Vector(public_key)], + // ) + Script::sample() +} + +pub fn encode_create_recovery_address_script() -> Script { + //Script::new(CREATE_RECOVERY_ADDRESS_CODE.to_vec(), vec![], vec![]) + Script::sample() +} + +pub fn encode_add_recovery_rotation_capability_script(_recovery_address: AccountAddress) -> Script { + // Script::new( + // ADD_RECOVERY_ROTATION_CAPABILITY_CODE.to_vec(), + // vec![], + // vec![TransactionArgument::Address(recovery_address)], + // ) + Script::sample() +} + +pub fn encode_rotate_authentication_key_with_recovery_address_script( + _recovery_address: AccountAddress, + _to_recover: AccountAddress, + _new_key: Vec, +) -> Script { + // Script::new( + // ROTATE_AUTHENTICATION_KEY_WITH_RECOVERY_ADDRESS_CODE.to_vec(), + // vec![], + // vec![ + // TransactionArgument::Address(recovery_address), + // TransactionArgument::Address(to_recover), + // TransactionArgument::U8Vector(new_key), + // ], + // ) + Script::sample() +} + +pub fn encode_tiered_mint_script( + coin_type: TypeTag, + sliding_nonce: u64, + designated_dealer_address: AccountAddress, + mint_amount: u64, + tier_index: u64, +) -> Script { + // Script::new( + // TIERED_MINT_CODE.to_vec(), + // vec![coin_type], + // vec![ + // TransactionArgument::U64(sliding_nonce), + // TransactionArgument::Address(designated_dealer_address), + // TransactionArgument::U64(mint_amount), + // TransactionArgument::U64(tier_index), + // ], + // ) + Script::sample() +} + +pub fn encode_set_validator_operator_with_nonce_admin_script( + _sliding_nonce: u64, + _operator_name: Vec, + _operator_account: AccountAddress, +) -> Script { + // Script::new( + // SET_VALIDATOR_OPERATOR_WITH_NONCE_ADMIN_CODE.to_vec(), + // vec![], + // vec![ + // TransactionArgument::U64(sliding_nonce), + // TransactionArgument::U8Vector(operator_name), + // TransactionArgument::Address(operator_account), + // ], + // ) + Script::sample() +} + +pub fn encode_set_validator_config_and_reconfigure_script( + _validator_account: AccountAddress, + _consensus_pubkey: Vec, + _validator_network_addresses: Vec, + _fullnode_network_addresses: Vec, +) -> Script { + // Script::new( + // SET_VALIDATOR_CONFIG_AND_RECONFIGURE_CODE.to_vec(), + // vec![], + // vec![ + // TransactionArgument::Address(validator_account), + // TransactionArgument::U8Vector(consensus_pubkey), + // TransactionArgument::U8Vector(validator_network_addresses), + // TransactionArgument::U8Vector(fullnode_network_addresses), + // ], + // ) + Script::sample() +} + +pub fn encode_remove_validators_payload(_validators: Vec) -> SignedUserTransaction { + // assert!(!validators.is_empty(), "Unexpected validator set length"); + // let mut script = template_path(); + // script.push("remove_validators.move"); + // + // let script = { + // let mut hb = Handlebars::new(); + // hb.set_strict_mode(true); + // hb.register_template_file("script", script).unwrap(); + // let mut data = HashMap::new(); + // data.insert("addresses", validators); + // + // let output = hb.render("script", &data).unwrap(); + // + // compile_admin_script(output.as_str()).unwrap() + // }; + // + // WriteSetPayload::Script { + // script, + // execute_as: diem_root_address(), + // } + SignedUserTransaction::sample() +} + +pub fn encode_custom_script( + _script_name_in_templates: &str, + _args: &T, + _execute_as: Option, +) -> SignedUserTransaction { + // let mut script = template_path(); + // script.push(script_name_in_templates); + // + // let script = { + // let mut hb = Handlebars::new(); + // hb.register_template_file("script", script).unwrap(); + // hb.set_strict_mode(true); + // let output = hb.render("script", args).unwrap(); + // + // compile_admin_script(output.as_str()).unwrap() + // }; + // + // WriteSetPayload::Script { + // script, + // execute_as: execute_as.unwrap_or_else(diem_root_address), + // } + SignedUserTransaction::sample() +} + +pub fn encode_halt_network_payload() -> SignedUserTransaction { + // let mut script = template_path(); + // script.push("halt_transactions.move"); + // + // WriteSetPayload::Script { + // script: Script::new( + // compile_script(script.to_str().unwrap().to_owned()), + // vec![], + // vec![], + // ), + // execute_as: diem_root_address(), + // } + SignedUserTransaction::sample() +} + +pub fn encode_rotate_authentication_key_script(_new_key: Vec) -> Script { + // Script::new( + // ROTATE_AUTHENTICATION_KEY_CODE.to_vec(), + // vec![], + // vec![TransactionArgument::U8Vector(new_key)], + // ) + Script::sample() +} + +pub fn encode_burn_txn_fees_script(_coin_type: TypeTag) -> Script { + //Script::new(BURN_TXN_FEES_CODE.to_vec(), vec![coin_type], vec![]) + Script::sample() +} + +pub fn encode_update_exchange_rate_script( + _currency: TypeTag, + _sliding_nonce: u64, + _new_exchange_rate_numerator: u64, + _new_exchange_rate_denominator: u64, +) -> Script { + // Script::new( + // UPDATE_EXCHANGE_RATE_CODE.to_vec(), + // vec![currency], + // vec![ + // TransactionArgument::U64(sliding_nonce), + // TransactionArgument::U64(new_exchange_rate_numerator), + // TransactionArgument::U64(new_exchange_rate_denominator), + // ], + // ) + Script::sample() +} diff --git a/vm/e2e-testsuite/src/tests/genesis.rs b/vm/e2e-testsuite/src/tests/genesis.rs index de3923a445..5242bc8e07 100644 --- a/vm/e2e-testsuite/src/tests/genesis.rs +++ b/vm/e2e-testsuite/src/tests/genesis.rs @@ -1,41 +1,44 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use starcoin_language_e2e_tests::common_transactions::peer_to_peer_txn; -use starcoin_language_e2e_tests::executor::FakeExecutor; -use starcoin_vm_types::transaction::Transaction; +use move_core_types::vm_status::KeptVMStatus; +use starcoin_language_e2e_tests::{common_transactions::peer_to_peer_txn, executor::FakeExecutor}; + +use starcoin_vm_types::transaction::{Transaction, TransactionStatus}; #[test] fn no_deletion_in_genesis() { - let genesis = GENESIS_CHANGE_SET.clone(); - assert!(!genesis.write_set().iter().any(|(_, op)| op.is_deletion())) + // let genesis = GENESIS_CHANGE_SET.clone(); + // assert!(!genesis.write_set().iter().any(|(_, op)| op.is_deletion())) } #[test] fn execute_genesis_write_set() { - let executor = FakeExecutor::no_genesis(); - let txn = Transaction::GenesisTransaction(WriteSetPayload::Direct(GENESIS_CHANGE_SET.clone())); - let mut output = executor.execute_transaction_block(vec![txn]).unwrap(); - - // Executing the genesis transaction should succeed - assert_eq!(output.len(), 1); - assert!(!output.pop().unwrap().status().is_discarded()) + // let executor = FakeExecutor::no_genesis(); + // let txn = Transaction::GenesisTransaction(WriteSetPayload::Direct(GENESIS_CHANGE_SET.clone())); + // let mut output = executor.execute_transaction_block(vec![txn]).unwrap(); + // + // // Executing the genesis transaction should succeed + // assert_eq!(output.len(), 1); + // assert!(!output.pop().unwrap().status().is_discarded()) + let (_, (_, transaction_info)) = FakeExecutor::from_test_genesis_with_info(); + assert_eq!(transaction_info.status().clone(), KeptVMStatus::Executed); } #[test] fn execute_genesis_and_drop_other_transaction() { let mut executor = FakeExecutor::no_genesis(); - let txn = Transaction::GenesisTransaction(WriteSetPayload::Direct(GENESIS_CHANGE_SET.clone())); + //let txn = Transaction::GenesisTransaction(WriteSetPayload::Direct(GENESIS_CHANGE_SET.clone())); let sender = executor.create_raw_account_data(1_000_000, 10); let receiver = executor.create_raw_account_data(100_000, 10); let txn2 = peer_to_peer_txn(sender.account(), receiver.account(), 11, 1000); let mut output = executor - .execute_transaction_block(vec![txn, Transaction::UserTransaction(txn2)]) + .execute_transaction_block(vec![Transaction::UserTransaction(txn2)]) .unwrap(); // Transaction that comes after genesis should be dropped. - assert_eq!(output.len(), 2); + assert_eq!(output.len(), 1); assert_eq!(output.pop().unwrap().status(), &TransactionStatus::Retry) } diff --git a/vm/e2e-testsuite/src/tests/genesis_initializations.rs b/vm/e2e-testsuite/src/tests/genesis_initializations.rs index fba5caaff7..e0284edf2c 100644 --- a/vm/e2e-testsuite/src/tests/genesis_initializations.rs +++ b/vm/e2e-testsuite/src/tests/genesis_initializations.rs @@ -151,14 +151,14 @@ fn test_diem_block_double_init() { let mut executor = FakeExecutor::stdlib_only_genesis(); executor.exec( - "DiemBlock", + "Block", "initialize_block_metadata", vec![], serialize_values(&vec![MoveValue::Signer(account_config::genesis_address())]), ); let output = executor.try_exec( - "DiemBlock", + "Block", "initialize_block_metadata", vec![], serialize_values(&vec![MoveValue::Signer(account_config::genesis_address())]), diff --git a/vm/e2e-testsuite/src/tests/mint.rs b/vm/e2e-testsuite/src/tests/mint.rs index 079e9a8e48..59bcba8336 100644 --- a/vm/e2e-testsuite/src/tests/mint.rs +++ b/vm/e2e-testsuite/src/tests/mint.rs @@ -1,7 +1,16 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 +use crate::tests::fake_stdlib::{ + encode_create_designated_dealer_script, encode_create_parent_vasp_account_script, + encode_tiered_mint_script, encode_update_exchange_rate_script, +}; +use move_core_types::vm_status::{known_locations, KeptVMStatus}; +use starcoin_language_e2e_tests::gas_costs::TXN_RESERVED; use starcoin_language_e2e_tests::test_with_different_versions; +use starcoin_language_e2e_tests::versioning::CURRENT_RELEASE_VERSIONS; +use starcoin_vm_types::account_config; +use starcoin_vm_types::transaction::TransactionStatus; #[test] fn tiered_mint_designated_dealer() { @@ -16,7 +25,7 @@ fn tiered_mint_designated_dealer() { blessed .transaction() .script(encode_create_designated_dealer_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, *dd.address(), dd.auth_key_prefix(), @@ -32,7 +41,7 @@ fn tiered_mint_designated_dealer() { blessed .transaction() .script(encode_tiered_mint_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 1, *dd.address(), mint_amount_one, @@ -45,9 +54,9 @@ fn tiered_mint_designated_dealer() { .read_account_resource(&dd) .expect("receiver must exist"); let dd_balance = executor - .read_balance_resource(&dd, account::xus_currency_code()) + .read_balance_resource(&dd) .expect("receiver balance must exist"); - assert_eq!(mint_amount_one, dd_balance.coin()); + assert_eq!(mint_amount_one, dd_balance.token() as u64); assert_eq!(0, dd_post_mint.sequence_number()); // -------------- @@ -57,7 +66,7 @@ fn tiered_mint_designated_dealer() { blessed .transaction() .script(encode_tiered_mint_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 2, *dd.address(), mint_amount_two, @@ -67,9 +76,9 @@ fn tiered_mint_designated_dealer() { .sign(), ); let dd_balance = executor - .read_balance_resource(&dd, account::xus_currency_code()) + .read_balance_resource(&dd) .expect("receiver balance must exist"); - assert_eq!(mint_amount_one + mint_amount_two, dd_balance.coin()); + assert_eq!(mint_amount_one + mint_amount_two, dd_balance.token() as u64); } } } @@ -90,7 +99,7 @@ fn mint_to_existing_not_dd() { blessed .transaction() .script(encode_create_parent_vasp_account_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, *receiver.address(), receiver.auth_key_prefix(), @@ -106,7 +115,7 @@ fn mint_to_existing_not_dd() { blessed .transaction() .script(encode_tiered_mint_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, *receiver.address(), mint_amount, @@ -143,7 +152,7 @@ fn mint_to_new_account() { let output = executor.execute_transaction( tc.transaction() .script(encode_tiered_mint_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, *new_account.address(), mint_amount, @@ -176,7 +185,7 @@ fn tiered_update_exchange_rate() { blessed .transaction() .script(encode_update_exchange_rate_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, 123, 100, diff --git a/vm/e2e-testsuite/src/tests/mod.rs b/vm/e2e-testsuite/src/tests/mod.rs index 821e7d3d98..94d4ca57a9 100644 --- a/vm/e2e-testsuite/src/tests/mod.rs +++ b/vm/e2e-testsuite/src/tests/mod.rs @@ -23,7 +23,8 @@ mod genesis; mod genesis_initializations; mod mint; mod module_publishing; -mod multi_agent; +// mod multi_agent; +mod fake_stdlib; mod on_chain_configs; mod parallel_execution; mod peer_to_peer; @@ -35,7 +36,6 @@ mod transaction_builder; mod transaction_fees; mod transaction_fuzzer; mod validator_set_management; -mod vasps; mod verify_txn; mod write_set; mod writeset_builder; diff --git a/vm/e2e-testsuite/src/tests/module_publishing.rs b/vm/e2e-testsuite/src/tests/module_publishing.rs index b4be6034c0..6e66f27f15 100644 --- a/vm/e2e-testsuite/src/tests/module_publishing.rs +++ b/vm/e2e-testsuite/src/tests/module_publishing.rs @@ -1,21 +1,18 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -// use diem_types::{ -// account_config::{self}, -// on_chain_config::VMPublishingOption, -// transaction::TransactionStatus, -// vm_status::{KeptVMStatus, StatusCode}, -// }; +use move_core_types::vm_status::{KeptVMStatus, StatusCode}; use starcoin_language_e2e_tests::{ account::Account, assert_prologue_parity, compile::compile_module, current_function_name, executor::FakeExecutor, transaction_status_eq, }; +use starcoin_types::account_config; +use starcoin_vm_types::transaction::TransactionStatus; // A module with an address different from the sender's address should be rejected #[test] fn bad_module_address() { - let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // create a transaction trying to publish a new module. @@ -65,7 +62,7 @@ macro_rules! module_republish_test { ($name:ident, $prog1:literal, $prog2:literal, $result:ident) => { #[test] fn $name() { - let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); let sequence_number = 2; @@ -266,8 +263,9 @@ module_republish_test!( #[test] pub fn test_publishing_no_modules_non_allowlist_script() { // create a FakeExecutor with a genesis from file - let mut executor = - FakeExecutor::from_genesis_with_options(VMPublishingOption::custom_scripts()); + // let mut executor = + // FakeExecutor::from_genesis_with_options(VMPublishingOption::custom_scripts()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // create a transaction trying to publish a new module. @@ -292,7 +290,10 @@ pub fn test_publishing_no_modules_non_allowlist_script() { .sign(); assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor + .verify_transaction(txn.clone()) + .unwrap() + .status_code(), executor.execute_transaction(txn).status(), StatusCode::INVALID_MODULE_PUBLISHER ); @@ -301,8 +302,9 @@ pub fn test_publishing_no_modules_non_allowlist_script() { #[test] pub fn test_publishing_no_modules_non_allowlist_script_proper_sender() { // create a FakeExecutor with a genesis from file - let mut executor = - FakeExecutor::from_genesis_with_options(VMPublishingOption::custom_scripts()); + // let mut executor = + // ::from_genesis_with_options(VMPublishingOption::custom_scripts()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // create a transaction trying to publish a new module. @@ -321,7 +323,7 @@ pub fn test_publishing_no_modules_non_allowlist_script_proper_sender() { .module(random_module) .sequence_number(0) .sign(); - assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!(executor.verify_transaction(txn.clone()), None); assert_eq!( executor.execute_transaction(txn).status(), &TransactionStatus::Keep(KeptVMStatus::Executed) @@ -350,7 +352,7 @@ pub fn test_publishing_no_modules_proper_sender() { .module(random_script) .sequence_number(0) .sign(); - assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!(executor.verify_transaction(txn.clone()), None); assert_eq!( executor.execute_transaction(txn).status(), &TransactionStatus::Keep(KeptVMStatus::Executed) @@ -381,7 +383,10 @@ pub fn test_publishing_no_modules_core_code_sender() { .sign(); // Doesn't work because the core code address doesn't exist assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor + .verify_transaction(txn.clone()) + .unwrap() + .status_code(), executor.execute_transaction(txn).status(), StatusCode::INVALID_MODULE_PUBLISHER ); @@ -413,7 +418,10 @@ pub fn test_publishing_no_modules_invalid_sender() { .sequence_number(10) .sign(); assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor + .verify_transaction(txn.clone()) + .unwrap() + .status_code(), executor.execute_transaction(txn).status(), StatusCode::INVALID_MODULE_PUBLISHER ); @@ -422,7 +430,7 @@ pub fn test_publishing_no_modules_invalid_sender() { #[test] pub fn test_publishing_allow_modules() { // create a FakeExecutor with a genesis from file - let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // create a transaction trying to publish a new module. @@ -444,7 +452,7 @@ pub fn test_publishing_allow_modules() { .module(random_script) .sequence_number(10) .sign(); - assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!(executor.verify_transaction(txn.clone()), None); assert_eq!( executor.execute_transaction(txn).status(), &TransactionStatus::Keep(KeptVMStatus::Executed) diff --git a/vm/e2e-testsuite/src/tests/multi_agent.rs b/vm/e2e-testsuite/src/tests/multi_agent.rs deleted file mode 100644 index 1ed345d040..0000000000 --- a/vm/e2e-testsuite/src/tests/multi_agent.rs +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// SPDX-License-Identifier: Apache-2.0 - -//! Tests for multi-agent transactions. - -#[test] -fn multi_agent_mint() { - let mut executor = FakeExecutor::from_genesis_file(); - executor.set_golden_file(current_function_name!()); - - let tc = Account::new_blessed_tc(); - - // account to represent designated dealer - let dd = executor.create_raw_account(); - executor.execute_and_apply( - tc.transaction() - .script(encode_create_designated_dealer_script( - account_config::xus_tag(), - 0, - *dd.address(), - dd.auth_key_prefix(), - vec![], - false, // add_all_currencies - )) - .sequence_number(0) - .sign(), - ); - - // account to represent VASP - let vasp = executor.create_raw_account(); - executor.execute_and_apply( - tc.transaction() - .script(encode_create_parent_vasp_account_script( - account_config::xus_tag(), - 0, - *vasp.address(), - vasp.auth_key_prefix(), - vec![], - false, // add_all_currencies - )) - .sequence_number(1) - .sign(), - ); - - let mint_amount = 1_000; - let tier_index = 0; - let txn = multi_agent_mint_txn(&tc, &dd, &vasp, 2, mint_amount, tier_index); - - // execute transaction - let output = executor.execute_transaction(txn); - assert_eq!( - output.status(), - &TransactionStatus::Keep(KeptVMStatus::Executed) - ); - - executor.apply_write_set(output.write_set()); - - let updated_tc = executor.read_account_resource(&tc).expect("tc must exist"); - let updated_dd = executor.read_account_resource(&dd).expect("dd must exist"); - let updated_vasp = executor - .read_account_resource(&vasp) - .expect("vasp must exist"); - let updated_dd_balance = executor - .read_balance_resource(&dd, account::xus_currency_code()) - .expect("dd balance must exist"); - let updated_vasp_balance = executor - .read_balance_resource(&vasp, account::xus_currency_code()) - .expect("vasp balance must exist"); - assert_eq!(0, updated_dd_balance.coin()); - assert_eq!(mint_amount, updated_vasp_balance.coin()); - assert_eq!(3, updated_tc.sequence_number()); - assert_eq!(0, updated_dd.sequence_number()); - assert_eq!(0, updated_vasp.sequence_number()); - assert_eq!(1, updated_dd.sent_events().count()); - assert_eq!(1, updated_vasp.received_events().count()); -} - -#[test] -fn multi_agent_swap() { - let mut executor = FakeExecutor::from_genesis_file(); - executor.set_golden_file(current_function_name!()); - // create and publish a sender with 1_000_010 XUS coins - // and a secondary signer with 100_100 XDX coins. - let mut sender = executor.create_raw_account_data(1_000_010, 10); - let mut secondary_signer = executor.create_xdx_raw_account_data(100_100, 100); - sender.add_balance_currency(xdx_currency_code()); - secondary_signer.add_balance_currency(xus_currency_code()); - - executor.add_account_data(&sender); - executor.add_account_data(&secondary_signer); - - let xus_amount = 10; - let xdx_amount = 100; - - let txn = multi_agent_swap_txn( - sender.account(), - secondary_signer.account(), - 10, - xus_amount, - xdx_amount, - ); - // execute transaction - let output = executor.execute_transaction(txn); - assert_eq!( - output.status(), - &TransactionStatus::Keep(KeptVMStatus::Executed) - ); - - executor.apply_write_set(output.write_set()); - - // check that numbers in stored DB are correct - let sender_xus_balance = 1_000_010 - xus_amount; - let secondary_signer_xdx_balance = 100_100 - xdx_amount; - let updated_sender = executor - .read_account_resource(sender.account()) - .expect("sender must exist"); - let updated_sender_xus_balance = executor - .read_balance_resource(sender.account(), account::xus_currency_code()) - .expect("sender xus balance must exist"); - let updated_sender_xdx_balance = executor - .read_balance_resource(sender.account(), account::xdx_currency_code()) - .expect("sender xdx balance must exist"); - let updated_secondary_signer = executor - .read_account_resource(secondary_signer.account()) - .expect("secondary signer must exist"); - let updated_secondary_signer_xus_balance = executor - .read_balance_resource(secondary_signer.account(), account::xus_currency_code()) - .expect("secondary signer xus balance must exist"); - let updated_secondary_signer_xdx_balance = executor - .read_balance_resource(secondary_signer.account(), account::xdx_currency_code()) - .expect("secondary signer xdx balance must exist"); - assert_eq!(sender_xus_balance, updated_sender_xus_balance.coin()); - assert_eq!(xdx_amount, updated_sender_xdx_balance.coin()); - assert_eq!(xus_amount, updated_secondary_signer_xus_balance.coin()); - assert_eq!( - secondary_signer_xdx_balance, - updated_secondary_signer_xdx_balance.coin() - ); - assert_eq!(11, updated_sender.sequence_number()); - assert_eq!(100, updated_secondary_signer.sequence_number()); - assert_eq!(1, updated_sender.received_events().count(),); - assert_eq!(1, updated_sender.sent_events().count()); - assert_eq!(1, updated_secondary_signer.received_events().count()); - assert_eq!(1, updated_secondary_signer.sent_events().count()); -} - -#[test] -fn multi_agent_p2p() { - let mut executor = FakeExecutor::from_genesis_file(); - executor.set_golden_file(current_function_name!()); - // create and publish a sender with 1_000_010 XUS coins - // and a secondary signer with 10 XUS coins. - let sender = executor.create_raw_account_data(1_000_010, 10); - let secondary_signer = executor.create_raw_account_data(10, 100); - - executor.add_account_data(&sender); - executor.add_account_data(&secondary_signer); - - let amount = 10; - - let txn = multi_agent_p2p_txn(sender.account(), secondary_signer.account(), 10, amount); - - // execute transaction - let output = executor.execute_transaction(txn); - assert_eq!( - output.status(), - &TransactionStatus::Keep(KeptVMStatus::Executed) - ); - - executor.apply_write_set(output.write_set()); - - // check that numbers in stored DB are correct - let sender_balance = 1_000_010 - amount; - let secondary_signer_balance = 10 + amount; - let updated_sender = executor - .read_account_resource(sender.account()) - .expect("sender must exist"); - let updated_sender_balance = executor - .read_balance_resource(sender.account(), account::xus_currency_code()) - .expect("sender xus balance must exist"); - let updated_secondary_signer = executor - .read_account_resource(secondary_signer.account()) - .expect("secondary signer must exist"); - let updated_secondary_signer_balance = executor - .read_balance_resource(secondary_signer.account(), account::xus_currency_code()) - .expect("secondary signer xus balance must exist"); - - assert_eq!(sender_balance, updated_sender_balance.coin()); - assert_eq!( - secondary_signer_balance, - updated_secondary_signer_balance.coin() - ); - assert_eq!(11, updated_sender.sequence_number()); - assert_eq!(100, updated_secondary_signer.sequence_number()); - assert_eq!(0, updated_sender.received_events().count(),); - assert_eq!(1, updated_sender.sent_events().count()); - assert_eq!(1, updated_secondary_signer.received_events().count()); - assert_eq!(0, updated_secondary_signer.sent_events().count()); -} - -#[test] -fn multi_agent_wrong_number_of_signers() { - let mut executor = FakeExecutor::from_genesis_file(); - executor.set_golden_file(current_function_name!()); - let sender = executor.create_raw_account_data(1_000_010, 10); - let secondary_signer = executor.create_raw_account_data(100_100, 100); - let third_signer = executor.create_raw_account_data(100_100, 100); - - executor.add_account_data(&sender); - executor.add_account_data(&secondary_signer); - executor.add_account_data(&third_signer); - - // Number of secondary signers given is 2 but the script only allows one secondary signer. - let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( - *sender.address(), - vec![*secondary_signer.address(), *third_signer.address()], - 10, - &sender.account().privkey, - sender.account().pubkey.clone(), - vec![ - &secondary_signer.account().privkey, - &third_signer.account().privkey, - ], - vec![ - secondary_signer.account().pubkey.clone(), - third_signer.account().pubkey.clone(), - ], - Some(multi_agent_swap_script(10, 0)), // swap between two accounts - ); - let output = executor.execute_transaction(signed_txn); - assert_eq!( - output.status(), - &TransactionStatus::Keep(KeptVMStatus::MiscellaneousError) - ); -} diff --git a/vm/e2e-testsuite/src/tests/on_chain_configs.rs b/vm/e2e-testsuite/src/tests/on_chain_configs.rs index 1ee00cf5d1..63671ab568 100644 --- a/vm/e2e-testsuite/src/tests/on_chain_configs.rs +++ b/vm/e2e-testsuite/src/tests/on_chain_configs.rs @@ -1,37 +1,23 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_framework_releases::legacy::transaction_scripts::LegacyStdlibScript; -use diem_transaction_builder::stdlib::encode_update_dual_attestation_limit_script; -use diem_types::{ - account_config::CORE_CODE_ADDRESS, - on_chain_config::DiemVersion, - transaction::{Script, ScriptFunction, TransactionArgument, TransactionStatus}, - vm_status::{KeptVMStatus, StatusCode}, -}; -use diem_vm::DiemVM; -use move_core_types::{ - identifier::Identifier, language_storage::ModuleId, transaction_argument::convert_txn_args, -}; +use move_core_types::vm_status::KeptVMStatus; use starcoin_language_e2e_tests::{ - account::{self, Account}, - assert_prologue_parity, - common_transactions::peer_to_peer_txn, - current_function_name, - executor::FakeExecutor, - test_with_different_versions, transaction_status_eq, - versioning::CURRENT_RELEASE_VERSIONS, + account::Account, assert_prologue_parity, current_function_name, executor::FakeExecutor, + test_with_different_versions, versioning::CURRENT_RELEASE_VERSIONS, +}; +use starcoin_vm_runtime::starcoin_vm::StarcoinVM; +use starcoin_vm_types::{ + transaction::{Script, TransactionStatus}, }; #[test] -fn initial_diem_version() { +fn initial_starcoin_version() { test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { - let mut executor = test_env.executor; - - let vm = DiemVM::new(executor.get_state_view()); + let vm = StarcoinVM::new(None); assert_eq!( - vm.internals().diem_version().unwrap(), + vm.get_version(), DiemVersion { major: test_env.version_number } ); @@ -50,7 +36,7 @@ fn initial_diem_version() { executor.new_block(); executor.execute_and_apply(txn); - let new_vm = DiemVM::new(executor.get_state_view()); + let new_vm = StarcoinVM::new(executor.get_state_view()); assert_eq!( new_vm.internals().diem_version().unwrap(), DiemVersion { major: test_env.version_number + 1 } @@ -63,7 +49,7 @@ fn initial_diem_version() { fn drop_txn_after_reconfiguration() { test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { let mut executor = test_env.executor; - let vm = DiemVM::new(executor.get_state_view()); + let vm = StarcoinVM::new(executor.get_state_view()); assert_eq!( vm.internals().diem_version().unwrap(), @@ -131,14 +117,14 @@ fn updated_limit_allows_txn() { &TransactionStatus::Keep(KeptVMStatus::Executed) )); let sender_balance = executor - .read_balance_resource(sender.account(), account::xus_currency_code()) + .read_balance_resource(sender.account()) .expect("sender balance must exist"); let receiver_balance = executor .read_balance_resource(receiver.account(), account::xus_currency_code()) .expect("receiver balance must exist"); - assert_eq!(3_999_990, sender_balance.coin()); - assert_eq!(1_000_010, receiver_balance.coin()); + assert_eq!(3_999_990, sender_balance.token() as u64); + assert_eq!(1_000_010, receiver_balance.token() as u64); } } } diff --git a/vm/e2e-testsuite/src/tests/parallel_execution.rs b/vm/e2e-testsuite/src/tests/parallel_execution.rs index 15f7d27285..d632b08dbe 100644 --- a/vm/e2e-testsuite/src/tests/parallel_execution.rs +++ b/vm/e2e-testsuite/src/tests/parallel_execution.rs @@ -1,13 +1,21 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use crate::tests::peer_to_peer::create_cyclic_transfers; +use crate::tests::peer_to_peer::{check_and_apply_transfer_output, create_cyclic_transfers}; +use move_core_types::vm_status::{KeptVMStatus, StatusCode}; +use move_ir_compiler::Compiler; +use starcoin_crypto::ed25519::Ed25519PrivateKey; +use starcoin_crypto::{HashValue, PrivateKey, Uniform}; +use starcoin_language_e2e_tests::common_transactions::rotate_key_txn; use starcoin_language_e2e_tests::executor::FakeExecutor; -use starcoin_vm_types::transaction::Transaction; +use starcoin_vm_runtime::parallel_executor::ParallelStarcoinVM; +use starcoin_vm_types::block_metadata::BlockMetadata; +use starcoin_vm_types::transaction::authenticator::AuthenticationKey; +use starcoin_vm_types::transaction::{Transaction, TransactionStatus}; #[test] fn peer_to_peer_with_prologue_parallel() { - let mut executor = FakeExecutor::from_fresh_genesis(); + let mut executor = FakeExecutor::from_test_genesis(); let account_size = 1000usize; let initial_balance = 2_000_000u64; let initial_seq_num = 10u64; @@ -36,7 +44,7 @@ fn peer_to_peer_with_prologue_parallel() { txns.insert(0, Transaction::BlockMetadata(new_block)); let (mut results, parallel_status) = - ParallelDiemVM::execute_block(txns, executor.get_state_view()).unwrap(); + ParallelStarcoinVM::execute_block(txns, executor.get_state_view()).unwrap(); assert!(parallel_status.is_none()); @@ -60,7 +68,7 @@ fn rotate_ed25519_key() { let txn = rotate_key_txn(sender.account(), new_key_hash.clone(), 10); // execute transaction - let (mut results, parallel_status) = ParallelDiemVM::execute_block( + let (mut results, parallel_status) = ParallelStarcoinVM::execute_block( vec![Transaction::UserTransaction(txn)], executor.get_state_view(), ) @@ -80,10 +88,10 @@ fn rotate_ed25519_key() { .read_account_resource(sender.account()) .expect("sender must exist"); let updated_sender_balance = executor - .read_balance_resource(sender.account(), account::xus_currency_code()) + .read_balance_resource(sender.account()) .expect("sender balance must exist"); assert_eq!(new_key_hash, updated_sender.authentication_key().to_vec()); - assert_eq!(balance, updated_sender_balance.coin()); + assert_eq!(balance, updated_sender_balance.token() as u64); assert_eq!(11, updated_sender.sequence_number()); // Check that transactions cannot be sent with the old key any more. diff --git a/vm/e2e-testsuite/src/tests/peer_to_peer.rs b/vm/e2e-testsuite/src/tests/peer_to_peer.rs index 3d1152aab9..bb2aa35f14 100644 --- a/vm/e2e-testsuite/src/tests/peer_to_peer.rs +++ b/vm/e2e-testsuite/src/tests/peer_to_peer.rs @@ -1,83 +1,95 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use starcoin_language_e2e_tests::account::Account; -use starcoin_language_e2e_tests::executor::FakeExecutor; +use move_core_types::vm_status::{known_locations, KeptVMStatus}; +use std::time::Instant; -#[test] -fn single_peer_to_peer_with_event() { - ::starcoin_logger::Logger::init_for_testing(); - test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { - let mut executor = test_env.executor; - // create and publish a sender with 1_000_000 coins and a receiver with 100_000 coins - let sender = executor.create_raw_account_data(1_000_000, 10); - let receiver = executor.create_raw_account_data(100_000, 10); - executor.add_account_data(&sender); - executor.add_account_data(&receiver); +use starcoin_language_e2e_tests::{ + account::Account, common_transactions::peer_to_peer_txn, executor::FakeExecutor, + test_with_different_versions, transaction_status_eq, versioning::CURRENT_RELEASE_VERSIONS, +}; - let transfer_amount = 1_000; - let txn = peer_to_peer_txn(sender.account(), receiver.account(), 10, transfer_amount); +use starcoin_vm_types::{ + account_config::{DepositEvent, WithdrawEvent}, + transaction::{SignedUserTransaction, TransactionOutput, TransactionStatus}, +}; - // execute transaction - let output = executor.execute_transaction(txn); - assert_eq!( - output.status(), - &TransactionStatus::Keep(KeptVMStatus::Executed) +#[test] +fn single_peer_to_peer_with_event() { + // ::starcoin_logger::Logger::init_for_testing(); + //test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + //let mut executor = test_env.executor; + // create and publish a sender with 1_000_000 coins and a receiver with 100_000 coins + let mut executor = FakeExecutor::from_test_genesis(); + let sender = executor.create_raw_account_data(1_000_000, 10); + let receiver = executor.create_raw_account_data(100_000, 10); + executor.add_account_data(&sender); + executor.add_account_data(&receiver); + + let transfer_amount = 1_000; + let txn = peer_to_peer_txn(sender.account(), receiver.account(), 10, transfer_amount); + + // execute transaction + let output = executor.execute_transaction(txn); + assert_eq!( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::Executed) + ); + + executor.apply_write_set(output.write_set()); + + // check that numbers in stored DB are correct + let sender_balance = 1_000_000 - transfer_amount; + let receiver_balance = 100_000 + transfer_amount; + let updated_sender = executor + .read_account_resource(sender.account()) + .expect("sender must exist"); + let updated_sender_balance = executor + .read_balance_resource(sender.account()) + .expect("sender balance must exist"); + let updated_receiver = executor + .read_account_resource(receiver.account()) + .expect("receiver must exist"); + let updated_receiver_balance = executor + .read_balance_resource(receiver.account()) + .expect("receiver balance must exist"); + assert_eq!(receiver_balance, updated_receiver_balance.token() as u64); + assert_eq!(sender_balance, updated_sender_balance.token() as u64); + assert_eq!(11, updated_sender.sequence_number()); + assert_eq!(0, updated_sender.deposit_events().count()); + assert_eq!(1, updated_sender.withdraw_events().count()); + assert_eq!(1, updated_receiver.deposit_events().count()); + assert_eq!(0, updated_receiver.withdraw_events().count()); + + let rec_ev_path = receiver.received_events_key().to_vec(); + let sent_ev_path = sender.sent_events_key().to_vec(); + for event in output.events() { + assert!( + rec_ev_path.as_slice() == event.key().as_bytes() + || sent_ev_path.as_slice() == event.key().as_bytes() ); - - executor.apply_write_set(output.write_set()); - - // check that numbers in stored DB are correct - let sender_balance = 1_000_000 - transfer_amount; - let receiver_balance = 100_000 + transfer_amount; - let updated_sender = executor - .read_account_resource(sender.account()) - .expect("sender must exist"); - let updated_sender_balance = executor - .read_balance_resource(sender.account(), account::xus_currency_code()) - .expect("sender balance must exist"); - let updated_receiver = executor - .read_account_resource(receiver.account()) - .expect("receiver must exist"); - let updated_receiver_balance = executor - .read_balance_resource(receiver.account(), account::xus_currency_code()) - .expect("receiver balance must exist"); - assert_eq!(receiver_balance, updated_receiver_balance.coin()); - assert_eq!(sender_balance, updated_sender_balance.coin()); - assert_eq!(11, updated_sender.sequence_number()); - assert_eq!(0, updated_sender.received_events().count(),); - assert_eq!(1, updated_sender.sent_events().count()); - assert_eq!(1, updated_receiver.received_events().count()); - assert_eq!(0, updated_receiver.sent_events().count()); - - let rec_ev_path = receiver.received_events_key().to_vec(); - let sent_ev_path = sender.sent_events_key().to_vec(); - for event in output.events() { - assert!( - rec_ev_path.as_slice() == event.key().as_bytes() - || sent_ev_path.as_slice() == event.key().as_bytes() - ); - } - } } + // } + //} } // TODO test no longer simple as the legacy version takes an &signer but all // new scripts take an owned signer // #[test] // fn single_peer_to_peer_with_padding() { -// ::diem_logger::Logger::init_for_testing(); +// //::diem_logger::Logger::init_for_testing(); // // create a FakeExecutor with a genesis from file -// let mut executor = -// FakeExecutor::from_genesis_with_options(VMPublishingOption::custom_scripts()); +// // let mut executor = +// // FakeExecutor::from_genesis_with_options(VMPublishingOption::custom_scripts()); +// let mut executor = FakeExecutor::from_test_genesis(); // executor.set_golden_file(current_function_name!()); - +// // // create and publish a sender with 1_000_000 coins and a receiver with 100_000 coins // let sender = executor.create_raw_account_data(1_000_000, 10); // let receiver = executor.create_raw_account_data(100_000, 10); // executor.add_account_data(&sender); // executor.add_account_data(&receiver); - +// // let transfer_amount = 1_000; // let padded_script = { // let mut script_mut = CompiledScript::deserialize( @@ -97,10 +109,10 @@ fn single_peer_to_peer_with_event() { // .unwrap() // .serialize(&mut script_bytes) // .unwrap(); - +// // Script::new( // script_bytes, -// vec![account_config::xus_tag()], +// vec![account_config::stc_type_tag()], // vec![ // TransactionArgument::Address(*receiver.address()), // TransactionArgument::U64(transfer_amount), @@ -109,7 +121,7 @@ fn single_peer_to_peer_with_event() { // ], // ) // }; - +// // let txn = sender // .account() // .transaction() @@ -124,9 +136,9 @@ fn single_peer_to_peer_with_event() { // output.status(), // &TransactionStatus::Keep(KeptVMStatus::Executed) // ); - +// // executor.apply_write_set(output.write_set()); - +// // // check that numbers in stored DB are correct // let sender_balance = 1_000_000 - transfer_amount; // let receiver_balance = 100_000 + transfer_amount; @@ -134,22 +146,21 @@ fn single_peer_to_peer_with_event() { // .read_account_resource(sender.account()) // .expect("sender must exist"); // let updated_sender_balance = executor -// .read_balance_resource(sender.account(), account::xus_currency_code()) +// .read_balance_resource(sender.account()) // .expect("sender balance must exist"); // let updated_receiver_balance = executor -// .read_balance_resource(receiver.account(), account::xus_currency_code()) +// .read_balance_resource(receiver.account()) // .expect("receiver balance must exist"); -// assert_eq!(receiver_balance, updated_receiver_balance.coin()); -// assert_eq!(sender_balance, updated_sender_balance.coin()); +// assert_eq!(receiver_balance, updated_receiver_balance.token()); +// assert_eq!(sender_balance, updated_sender_balance.token()); // assert_eq!(11, updated_sender.sequence_number()); // } - #[test] fn few_peer_to_peer_with_event() { test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { let mut executor = test_env.executor; - // create and publish a sender with 3_000_000 coins and a receiver with 3_000_000 coins + // create and publish a sender with 3_000_000 coins and a receiver with 3_000_000 coins= let sender = executor.create_raw_account_data(3_000_000, 10); let receiver = executor.create_raw_account_data(3_000_000, 10); executor.add_account_data(&sender); @@ -158,7 +169,7 @@ fn few_peer_to_peer_with_event() { let transfer_amount = 1_000; // execute transaction - let txns: Vec = vec![ + let txns: Vec = vec![ peer_to_peer_txn(sender.account(), receiver.account(), 10, transfer_amount), peer_to_peer_txn(sender.account(), receiver.account(), 11, transfer_amount), peer_to_peer_txn(sender.account(), receiver.account(), 12, transfer_amount), @@ -173,47 +184,47 @@ fn few_peer_to_peer_with_event() { // check events for event in txn_output.events() { - if let Ok(payload) = SentPaymentEvent::try_from(event) { - assert_eq!(transfer_amount, payload.amount()); - assert_eq!(receiver.address(), &payload.receiver()); - } else if let Ok(payload) = ReceivedPaymentEvent::try_from(event) { - assert_eq!(transfer_amount, payload.amount()); - assert_eq!(sender.address(), &payload.sender()); + if let Ok(payload) = WithdrawEvent::try_from_bytes(event.event_data()) { + assert_eq!(transfer_amount, payload.amount() as u64); + //assert_eq!(receiver.address(), &payload.receiver()); + } else if let Ok(payload) = DepositEvent::try_from_bytes(event.event_data()) { + assert_eq!(transfer_amount, payload.amount() as u64); + //assert_eq!(sender.address(), &payload.sender()); } else { panic!("Unexpected Event Type") } } let original_sender_balance = executor - .read_balance_resource(sender.account(), account::xus_currency_code()) + .read_balance_resource(sender.account()) .expect("sender balance must exist"); let original_receiver_balance = executor - .read_balance_resource(receiver.account(), account::xus_currency_code()) + .read_balance_resource(receiver.account()) .expect("receiver balcne must exist"); executor.apply_write_set(txn_output.write_set()); // check that numbers in stored DB are correct - let sender_balance = original_sender_balance.coin() - transfer_amount; - let receiver_balance = original_receiver_balance.coin() + transfer_amount; + let sender_balance = (original_sender_balance.token() as u64) - transfer_amount; + let receiver_balance = (original_receiver_balance.token() as u64) + transfer_amount; let updated_sender = executor .read_account_resource(sender.account()) .expect("sender must exist"); let updated_sender_balance = executor - .read_balance_resource(sender.account(), account::xus_currency_code()) + .read_balance_resource(sender.account()) .expect("sender balance must exist"); let updated_receiver = executor .read_account_resource(receiver.account()) .expect("receiver must exist"); let updated_receiver_balance = executor - .read_balance_resource(receiver.account(), account::xus_currency_code()) + .read_balance_resource(receiver.account()) .expect("receiver balance must exist"); - assert_eq!(receiver_balance, updated_receiver_balance.coin()); - assert_eq!(sender_balance, updated_sender_balance.coin()); + assert_eq!(receiver_balance, updated_receiver_balance.token() as u64); + assert_eq!(sender_balance, updated_sender_balance.token() as u64); assert_eq!(11 + idx as u64, updated_sender.sequence_number()); - assert_eq!(0, updated_sender.received_events().count()); - assert_eq!(idx as u64 + 1, updated_sender.sent_events().count()); - assert_eq!(idx as u64 + 1, updated_receiver.received_events().count()); - assert_eq!(0, updated_receiver.sent_events().count()); + assert_eq!(0, updated_sender.withdraw_events().count()); + assert_eq!(idx as u64 + 1, updated_sender.withdraw_events().count()); + assert_eq!(idx as u64 + 1, updated_receiver.deposit_events().count()); + assert_eq!(0, updated_receiver.withdraw_events().count()); } } } @@ -222,33 +233,34 @@ fn few_peer_to_peer_with_event() { /// Test that a zero-amount transaction fails, per policy. #[test] fn zero_amount_peer_to_peer() { - test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { - let mut executor = test_env.executor; - let sequence_number = 10; - let sender = executor.create_raw_account_data(1_000_000, sequence_number); - let receiver = executor.create_raw_account_data(100_000, sequence_number); - executor.add_account_data(&sender); - executor.add_account_data(&receiver); - - let transfer_amount = 0; - let txn = peer_to_peer_txn( - sender.account(), - receiver.account(), - sequence_number, - transfer_amount, - ); - - let output = &executor.execute_transaction(txn); - // Error code 7 means that the transaction was a zero-amount one. - assert!(transaction_status_eq( - output.status(), - &TransactionStatus::Keep(KeptVMStatus::MoveAbort( - known_locations::diem_account_module_abort(), - 519 - )), - )); - } - } + //test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { + //let mut executor = test_env.executor; + let mut executor = FakeExecutor::from_test_genesis(); + let sequence_number = 10; + let sender = executor.create_raw_account_data(1_000_000, sequence_number); + let receiver = executor.create_raw_account_data(100_000, sequence_number); + executor.add_account_data(&sender); + executor.add_account_data(&receiver); + + let transfer_amount = 0; + let txn = peer_to_peer_txn( + sender.account(), + receiver.account(), + sequence_number, + transfer_amount, + ); + + let output = &executor.execute_transaction(txn); + // Error code 7 means that the transaction was a zero-amount one. + assert!(transaction_status_eq( + output.status(), + &TransactionStatus::Keep(KeptVMStatus::MoveAbort( + known_locations::diem_account_module_abort(), + 519, + )), + )); + //} + //} } // Holder for transaction data; arguments to transactions. @@ -274,8 +286,8 @@ pub(crate) fn create_cyclic_transfers( executor: &FakeExecutor, accounts: &[Account], transfer_amount: u64, -) -> (Vec, Vec) { - let mut txns: Vec = Vec::new(); +) -> (Vec, Vec) { + let mut txns: Vec = Vec::new(); let mut txns_info: Vec = Vec::new(); // loop through all transactions and let each transfer the same amount to the next one let count = accounts.len(); @@ -300,8 +312,8 @@ fn create_one_to_many_transfers( executor: &FakeExecutor, accounts: &[Account], transfer_amount: u64, -) -> (Vec, Vec) { - let mut txns: Vec = Vec::new(); +) -> (Vec, Vec) { + let mut txns: Vec = Vec::new(); let mut txns_info: Vec = Vec::new(); // grab account 0 as a sender let sender = &accounts[0]; @@ -327,8 +339,8 @@ fn create_many_to_one_transfers( executor: &FakeExecutor, accounts: &[Account], transfer_amount: u64, -) -> (Vec, Vec) { - let mut txns: Vec = Vec::new(); +) -> (Vec, Vec) { + let mut txns: Vec = Vec::new(); let mut txns_info: Vec = Vec::new(); // grab account 0 as a sender let receiver = &accounts[0]; @@ -368,33 +380,33 @@ pub(crate) fn check_and_apply_transfer_output( .read_account_resource(sender) .expect("sender must exist"); let sender_balance = executor - .read_balance_resource(sender, account::xus_currency_code()) + .read_balance_resource(sender) .expect("sender balance must exist"); - let sender_initial_balance = sender_balance.coin(); + let sender_initial_balance = sender_balance.token(); let sender_seq_num = sender_resource.sequence_number(); let receiver_initial_balance = executor - .read_balance_resource(receiver, account::xus_currency_code()) + .read_balance_resource(receiver) .expect("receiver balance must exist") - .coin(); + .token(); // apply single transaction to DB let txn_output = &output[i]; executor.apply_write_set(txn_output.write_set()); // check that numbers stored in DB are correct - let sender_balance = sender_initial_balance - transfer_amount; - let receiver_balance = receiver_initial_balance + transfer_amount; + let sender_balance = sender_initial_balance as u64 - transfer_amount; + let receiver_balance = receiver_initial_balance as u64 + transfer_amount; let updated_sender = executor .read_account_resource(sender) .expect("sender must exist"); let updated_sender_balance = executor - .read_balance_resource(sender, account::xus_currency_code()) + .read_balance_resource(sender) .expect("sender balance must exist"); let updated_receiver_balance = executor - .read_balance_resource(receiver, account::xus_currency_code()) + .read_balance_resource(receiver) .expect("receiver balance must exist"); - assert_eq!(receiver_balance, updated_receiver_balance.coin()); - assert_eq!(sender_balance, updated_sender_balance.coin()); + assert_eq!(receiver_balance, updated_receiver_balance.token() as u64); + assert_eq!(sender_balance, updated_sender_balance.token() as u64); assert_eq!(sender_seq_num + 1, updated_sender.sequence_number()); } } diff --git a/vm/e2e-testsuite/src/tests/preburn_queue.rs b/vm/e2e-testsuite/src/tests/preburn_queue.rs index 882891356a..edbf72d104 100644 --- a/vm/e2e-testsuite/src/tests/preburn_queue.rs +++ b/vm/e2e-testsuite/src/tests/preburn_queue.rs @@ -1,12 +1,16 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_transaction_builder::stdlib::*; -use diem_types::{account_config, transaction::TransactionOutput}; +use crate::tests::fake_stdlib::{ + encode_burn_script, encode_burn_with_amount_script_function, encode_cancel_burn_script, + encode_cancel_burn_with_amount_script_function, encode_preburn_script, +}; use move_core_types::vm_status::{DiscardedVMStatus, KeptVMStatus}; use starcoin_language_e2e_tests::{ account::Account, current_function_name, executor::FakeExecutor, utils, }; +use starcoin_types::account_config; +use starcoin_vm_types::transaction::TransactionOutput; fn create_preburn_balance( executor: &mut FakeExecutor, @@ -15,7 +19,7 @@ fn create_preburn_balance( dd_seqno: &mut u64, should_fail: bool, ) -> Option { - let script = encode_preburn_script(account_config::xus_tag(), preburn_amount); + let script = encode_preburn_script(account_config::stc_type_tag(), preburn_amount); let txn = dd_account .transaction() .script(script) @@ -39,9 +43,9 @@ fn burn_old( let txn = tc_account .transaction() .script(encode_burn_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, - account_config::testnet_dd_account_address(), + account_config::genesis_address(), )) .sequence_number(*tc_seqno) .sign(); @@ -63,8 +67,8 @@ fn cancel_burn_old( let txn = tc_account .transaction() .script(encode_cancel_burn_script( - account_config::xus_tag(), - account_config::testnet_dd_account_address(), + account_config::stc_type_tag(), + account_config::genesis_address(), )) .sequence_number(*tc_seqno) .sign(); @@ -87,9 +91,9 @@ fn burn_with_amount_new( let txn = tc_account .transaction() .payload(encode_burn_with_amount_script_function( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, - account_config::testnet_dd_account_address(), + account_config::genesis_address(), amount, )) .sequence_number(*tc_seqno) @@ -113,8 +117,8 @@ fn cancel_burn_with_amount_new( let txn = tc_account .transaction() .payload(encode_cancel_burn_with_amount_script_function( - account_config::xus_tag(), - account_config::testnet_dd_account_address(), + account_config::stc_type_tag(), + account_config::genesis_address(), amount, )) .sequence_number(*tc_seqno) diff --git a/vm/e2e-testsuite/src/tests/rotate_key.rs b/vm/e2e-testsuite/src/tests/rotate_key.rs index 54bba22058..f8e031c4ce 100644 --- a/vm/e2e-testsuite/src/tests/rotate_key.rs +++ b/vm/e2e-testsuite/src/tests/rotate_key.rs @@ -1,22 +1,14 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_keygen::KeyGen; -use diem_types::{ - transaction::{authenticator::AuthenticationKey, SignedTransaction, TransactionStatus}, - vm_status::{KeptVMStatus, StatusCode}, -}; -use starcoin_crypto::{ - ed25519::Ed25519PrivateKey, - multi_ed25519::{MultiEd25519PublicKey, MultiEd25519Signature}, - PrivateKey, SigningKey, Uniform, -}; +use move_core_types::vm_status::{KeptVMStatus, StatusCode}; +use starcoin_crypto::ed25519::Ed25519PrivateKey; +use starcoin_crypto::{PrivateKey, Uniform}; use starcoin_language_e2e_tests::{ - account, - common_transactions::{raw_rotate_key_txn, rotate_key_txn}, - test_with_different_versions, + common_transactions::rotate_key_txn, test_with_different_versions, versioning::CURRENT_RELEASE_VERSIONS, }; +use starcoin_vm_types::transaction::{authenticator::AuthenticationKey, TransactionStatus}; #[test] fn rotate_ed25519_key() { @@ -46,10 +38,10 @@ fn rotate_ed25519_key() { .read_account_resource(sender.account()) .expect("sender must exist"); let updated_sender_balance = executor - .read_balance_resource(sender.account(), account::xus_currency_code()) + .read_balance_resource(sender.account()) .expect("sender balance must exist"); assert_eq!(new_key_hash, updated_sender.authentication_key().to_vec()); - assert_eq!(balance, updated_sender_balance.coin()); + assert_eq!(balance, updated_sender_balance.token()); assert_eq!(11, updated_sender.sequence_number()); // Check that transactions cannot be sent with the old key any more. @@ -72,69 +64,69 @@ fn rotate_ed25519_key() { } } -#[test] -fn rotate_ed25519_multisig_key() { - test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { - let mut executor = test_env.executor; - - let mut seq_number = 10; - // create and publish sender - let sender = executor.create_raw_account_data(1_000_000, seq_number); - executor.add_account_data(&sender); - let _sender_address = sender.address(); - - // create a 1-of-2 multisig policy - let mut keygen = KeyGen::from_seed([9u8; 32]); - - let (privkey1, pubkey1) = keygen.generate_keypair(); - let (privkey2, pubkey2) = keygen.generate_keypair(); - let threshold = 1; - let multi_ed_public_key = - MultiEd25519PublicKey::new(vec![pubkey1, pubkey2], threshold).unwrap(); - let new_auth_key = AuthenticationKey::multi_ed25519(&multi_ed_public_key); - - // (1) rotate key to multisig - let output = &executor.execute_transaction(rotate_key_txn( - sender.account(), - new_auth_key.to_vec(), - seq_number, - )); - assert_eq!( - output.status(), - &TransactionStatus::Keep(KeptVMStatus::Executed), - ); - executor.apply_write_set(output.write_set()); - seq_number += 1; - - // (2) send a tx signed by privkey 1 - let txn1 = raw_rotate_key_txn(sender.account(), new_auth_key.to_vec(), seq_number); - let signature1 = MultiEd25519Signature::from(privkey1.sign(&txn1)); - let signed_txn1 = - SignedTransaction::new_multisig(txn1, multi_ed_public_key.clone(), signature1); - let output = &executor.execute_transaction(signed_txn1); - assert_eq!( - output.status(), - &TransactionStatus::Keep(KeptVMStatus::Executed), - ); - executor.apply_write_set(output.write_set()); - seq_number += 1; - - // (3) send a tx signed by privkey 2 - let txn2 = raw_rotate_key_txn(sender.account(), new_auth_key.to_vec(), seq_number); - let pubkey_index = 1; - let signature2 = - MultiEd25519Signature::new(vec![(privkey2.sign(&txn2), pubkey_index)]).unwrap(); - let signed_txn2 = SignedTransaction::new_multisig(txn2, multi_ed_public_key, signature2); - signed_txn2.clone().check_signature().unwrap(); - let output = &executor.execute_transaction(signed_txn2); - assert_eq!( - output.status(), - &TransactionStatus::Keep(KeptVMStatus::Executed), - ); - } - } -} +// TODO(BobOng): e2e-testsuit no support multisig +//#[test] +// fn rotate_ed25519_multisig_key() { +// test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { +// let mut executor = test_env.executor; +// +// let mut seq_number = 10; +// // create and publish sender +// let sender = executor.create_raw_account_data(1_000_000, seq_number); +// executor.add_account_data(&sender); +// let _sender_address = sender.address(); +// +// // create a 1-of-2 multisig policy +// let mut keygen = KeyGen::from_seed([9u8; 32]); +// +// let (privkey1, pubkey1) = keygen.generate_keypair(); +// let (privkey2, pubkey2) = keygen.generate_keypair(); +// let threshold = 1; +// let multi_ed_public_key = +// MultiEd25519PublicKey::new(vec![pubkey1, pubkey2], threshold).unwrap(); +// let new_auth_key = AuthenticationKey::multi_ed25519(&multi_ed_public_key); +// +// // (1) rotate key to multisig +// let output = &executor.execute_transaction(rotate_key_txn( +// sender.account(), +// new_auth_key.to_vec(), +// seq_number, +// )); +// assert_eq!( +// output.status(), +// &TransactionStatus::Keep(KeptVMStatus::Executed), +// ); +// executor.apply_write_set(output.write_set()); +// seq_number += 1; +// +// // (2) send a tx signed by privkey 1 +// let txn1 = raw_rotate_key_txn(sender.account(), new_auth_key.to_vec(), seq_number); +// let signature1 = MultiEd25519Signature::from(privkey1.sign(&txn1)); +// let signed_txn1 = +// SignedUserTransaction::new_multisig(txn1, multi_ed_public_key.clone(), signature1); +// let output = &executor.execute_transaction(signed_txn1); +// assert_eq!( +// output.status(), +// &TransactionStatus::Keep(KeptVMStatus::Executed), +// ); +// executor.apply_write_set(output.write_set()); +// seq_number += 1; +// +// // (3) send a tx signed by privkey 2 +// let txn2 = raw_rotate_key_txn(sender.account(), new_auth_key.to_vec(), seq_number); +// let pubkey_index = 1; +// let signature2 = +// MultiEd25519Signature::new(vec![(privkey2.sign(&txn2), pubkey_index)]).unwrap(); +// let signed_txn2 = SignedUserTransaction::new_multisig(txn2, multi_ed_public_key, signature2); +// signed_txn2.clone().check_signature().unwrap(); +// let output = &executor.execute_transaction(signed_txn2); +// assert_eq!( +// output.status(), +// &TransactionStatus::Keep(KeptVMStatus::Executed), +// ); +// } +// } +// } #[test] - fn rotate_shared_ed25519_public_key() {} diff --git a/vm/e2e-testsuite/src/tests/script_functions.rs b/vm/e2e-testsuite/src/tests/script_functions.rs index 774544965f..9ae6242e48 100644 --- a/vm/e2e-testsuite/src/tests/script_functions.rs +++ b/vm/e2e-testsuite/src/tests/script_functions.rs @@ -1,17 +1,15 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_types::{ - on_chain_config::DIEM_VERSION_2, - transaction::{ScriptFunction, TransactionStatus}, - vm_status::{DiscardedVMStatus, KeptVMStatus}, -}; -use move_core_types::{identifier::Identifier, language_storage::ModuleId}; +use move_core_types::identifier::Identifier; +use move_core_types::language_storage::ModuleId; +use move_core_types::vm_status::{DiscardedVMStatus, KeptVMStatus}; use starcoin_language_e2e_tests::{ account::Account, compile::compile_module, current_function_name, executor::FakeExecutor, - transaction_status_eq, utils, + transaction_status_eq, utils, versioning::CURRENT_RELEASE_VERSIONS, }; +use starcoin_vm_types::transaction::{ScriptFunction, TransactionStatus}; fn prepare_module(executor: &mut FakeExecutor, account: &Account, seq_num: u64) -> u64 { let program = format!( " @@ -87,7 +85,7 @@ fn script_fn_payload_invoke_private_fn() { &mut executor, &dr_account, &mut dr_seqno, - Some(DIEM_VERSION_2.major), + Some(CURRENT_RELEASE_VERSIONS.max().unwrap()), ); let output = executor.execute_transaction(txn); @@ -131,7 +129,7 @@ fn script_fn_payload_invoke_public_fn() { &mut executor, &dr_account, &mut dr_seqno, - Some(DIEM_VERSION_2.major), + Some(CURRENT_RELEASE_VERSIONS.max().unwrap()), ); let output = executor.execute_transaction(txn); @@ -175,7 +173,7 @@ fn script_fn_payload_invoke_script_fn() { &mut executor, &dr_account, &mut dr_seqno, - Some(DIEM_VERSION_2.major), + Some(CURRENT_RELEASE_VERSIONS.max().unwrap()), ); let output = executor.execute_transaction(txn); diff --git a/vm/e2e-testsuite/src/tests/scripts.rs b/vm/e2e-testsuite/src/tests/scripts.rs index 85735a633d..1107af3b67 100644 --- a/vm/e2e-testsuite/src/tests/scripts.rs +++ b/vm/e2e-testsuite/src/tests/scripts.rs @@ -1,26 +1,24 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_types::{ - account_address::AccountAddress, - account_config, - on_chain_config::VMPublishingOption, - transaction::{Script, TransactionStatus}, - vm_status::KeptVMStatus, -}; use move_binary_format::file_format::{ empty_script, AbilitySet, AddressIdentifierIndex, Bytecode, FunctionHandle, FunctionHandleIndex, IdentifierIndex, ModuleHandle, ModuleHandleIndex, SignatureIndex, }; +use move_core_types::account_address::AccountAddress; +use move_core_types::vm_status::KeptVMStatus; use move_core_types::{ identifier::Identifier, language_storage::{StructTag, TypeTag}, }; -use starcoin_language_e2e_tests::{account, current_function_name, executor::FakeExecutor}; +use starcoin_language_e2e_tests::{current_function_name, executor::FakeExecutor}; +use starcoin_types::account_config; +use starcoin_vm_types::transaction::{Script, TransactionStatus}; #[test] fn script_code_unverifiable() { - let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + //let mut executor = FakeExecutor::from_genesis_with_options(VMConfig::default()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // create and publish sender @@ -60,15 +58,15 @@ fn script_code_unverifiable() { .read_account_resource(sender.account()) .expect("sender must exist"); let updated_sender_balance = executor - .read_balance_resource(sender.account(), account::xus_currency_code()) + .read_balance_resource(sender.account()) .expect("sender balance must exist"); - assert_eq!(balance, updated_sender_balance.coin()); + assert_eq!(balance, updated_sender_balance.token() as u64); assert_eq!(11, updated_sender.sequence_number()); } #[test] fn script_none_existing_module_dep() { - let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // create and publish sender @@ -136,15 +134,15 @@ fn script_none_existing_module_dep() { .read_account_resource(sender.account()) .expect("sender must exist"); let updated_sender_balance = executor - .read_balance_resource(sender.account(), account::xus_currency_code()) + .read_balance_resource(sender.account()) .expect("sender balance must exist"); - assert_eq!(balance, updated_sender_balance.coin()); + assert_eq!(balance, updated_sender_balance.token() as u64); assert_eq!(11, updated_sender.sequence_number()); } #[test] fn script_non_existing_function_dep() { - let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // create and publish sender @@ -212,15 +210,15 @@ fn script_non_existing_function_dep() { .read_account_resource(sender.account()) .expect("sender must exist"); let updated_sender_balance = executor - .read_balance_resource(sender.account(), account::xus_currency_code()) + .read_balance_resource(sender.account()) .expect("sender balance must exist"); - assert_eq!(balance, updated_sender_balance.coin()); + assert_eq!(balance, updated_sender_balance.token() as u64); assert_eq!(11, updated_sender.sequence_number()); } #[test] fn script_bad_sig_function_dep() { - let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // create and publish sender @@ -289,15 +287,15 @@ fn script_bad_sig_function_dep() { .read_account_resource(sender.account()) .expect("sender must exist"); let updated_sender_balance = executor - .read_balance_resource(sender.account(), account::xus_currency_code()) + .read_balance_resource(sender.account()) .expect("sender balance must exist"); - assert_eq!(balance, updated_sender_balance.coin()); + assert_eq!(balance, updated_sender_balance.token() as u64); assert_eq!(11, updated_sender.sequence_number()); } #[test] fn script_type_argument_module_does_not_exist() { - let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // create and publish sender @@ -326,12 +324,12 @@ fn script_type_argument_module_does_not_exist() { .transaction() .script(Script::new( blob, - vec![TypeTag::Struct(StructTag { + vec![TypeTag::Struct(Box::new(StructTag { address, module, name: Identifier::new("fake").unwrap(), type_params: vec![], - })], + }))], vec![], )) .sequence_number(10) @@ -354,15 +352,15 @@ fn script_type_argument_module_does_not_exist() { .read_account_resource(sender.account()) .expect("sender must exist"); let updated_sender_balance = executor - .read_balance_resource(sender.account(), account::xus_currency_code()) + .read_balance_resource(sender.account()) .expect("sender balance must exist"); - assert_eq!(balance, updated_sender_balance.coin()); + assert_eq!(balance, updated_sender_balance.token() as u64); assert_eq!(11, updated_sender.sequence_number()); } #[test] fn script_nested_type_argument_module_does_not_exist() { - let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // create and publish sender @@ -391,12 +389,14 @@ fn script_nested_type_argument_module_does_not_exist() { .transaction() .script(Script::new( blob, - vec![TypeTag::Vector(Box::new(TypeTag::Struct(StructTag { - address, - module, - name: Identifier::new("fake").unwrap(), - type_params: vec![], - })))], + vec![TypeTag::Vector(Box::new(TypeTag::Struct(Box::new( + StructTag { + address, + module, + name: Identifier::new("fake").unwrap(), + type_params: vec![], + }, + ))))], vec![], )) .sequence_number(10) @@ -419,8 +419,8 @@ fn script_nested_type_argument_module_does_not_exist() { .read_account_resource(sender.account()) .expect("sender must exist"); let updated_sender_balance = executor - .read_balance_resource(sender.account(), account::xus_currency_code()) + .read_balance_resource(sender.account()) .expect("sender balance must exist"); - assert_eq!(balance, updated_sender_balance.coin()); + assert_eq!(balance, updated_sender_balance.token() as u64); assert_eq!(11, updated_sender.sequence_number()); } diff --git a/vm/e2e-testsuite/src/tests/transaction_builder.rs b/vm/e2e-testsuite/src/tests/transaction_builder.rs index 7f2b0acfa9..39ec369941 100644 --- a/vm/e2e-testsuite/src/tests/transaction_builder.rs +++ b/vm/e2e-testsuite/src/tests/transaction_builder.rs @@ -8,27 +8,33 @@ #![forbid(unsafe_code)] -use starcoin_crypto::{ed25519::Ed25519PrivateKey, traits::SigningKey, PrivateKey, Uniform}; -// use diem_keygen::KeyGen; -use move_core_types::language_storage::TypeTag; +use move_core_types::vm_status::StatusCode; +use move_core_types::{ + account_address::AccountAddress, language_storage::TypeTag, vm_status::KeptVMStatus, +}; +use starcoin_crypto::keygen::KeyGen; +use starcoin_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, SigningKey, Uniform}; + use starcoin_language_e2e_tests::{ - account::{self, Account}, - common_transactions::rotate_key_txn, - //currencies, current_function_name, - executor::FakeExecutor, - gas_costs, - test_with_different_versions, + common_transactions::rotate_key_txn, gas_costs, test_with_different_versions, versioning::CURRENT_RELEASE_VERSIONS, }; -use starcoin_transaction_builder::stdlib::*; -use starcoin_types::{ - account_address::AccountAddress, - account_config, - transaction::{ - authenticator::AuthenticationKey, Script, TransactionOutput, TransactionStatus, - WriteSetPayload, - }, - vm_status::{KeptVMStatus, StatusCode}, + +use starcoin_types::account_config; + +use starcoin_vm_types::transaction::{ + authenticator::AuthenticationKey, Script, TransactionOutput, TransactionStatus, +}; + +use crate::tests::fake_stdlib::{ + encode_add_recovery_rotation_capability_script, encode_create_child_vasp_account_script, + encode_create_designated_dealer_script, encode_create_parent_vasp_account_script, + encode_create_recovery_address_script, encode_freeze_account_script, + encode_peer_to_peer_with_metadata_script, encode_publish_shared_ed25519_public_key_script, + encode_rotate_authentication_key_with_nonce_admin_script, + encode_rotate_authentication_key_with_recovery_address_script, + encode_rotate_dual_attestation_info_script, encode_rotate_shared_ed25519_public_key_script, + encode_unfreeze_account_script, }; const XUS_THRESHOLD: u64 = 10_000_000_000 / 5; @@ -40,6 +46,7 @@ const PAYEE_COMPLIANCE_KEY_NOT_SET_ERROR_CODE: u64 = 1281; fn test_rotate_authentication_key_with_nonce_admin() { test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { let mut executor = test_env.executor; + //let mut executor = FakeExecutor::from_test_genesis(); let new_account = executor.create_raw_account_data(100_000, 0); executor.add_account_data(&new_account); @@ -48,14 +55,19 @@ fn test_rotate_authentication_key_with_nonce_admin() { let new_key_hash = AuthenticationKey::ed25519(&pubkey).to_vec(); let account = test_env.dr_account; + // let txn = account + // .transaction() + // .write_set(WriteSetPayload::Script { + // script: encode_rotate_authentication_key_with_nonce_admin_script(0, new_key_hash.clone()), + // execute_as: *new_account.address(), + // }) + // .sequence_number(test_env.dr_sequence_number) + // .sign(); let txn = account - .transaction() - .write_set(WriteSetPayload::Script { - script: encode_rotate_authentication_key_with_nonce_admin_script(0, new_key_hash.clone()), - execute_as: *new_account.address(), - }) + .transaction().script(encode_rotate_authentication_key_with_nonce_admin_script(0, new_key_hash.clone())) .sequence_number(test_env.dr_sequence_number) .sign(); + executor.new_block(); let output = executor.execute_and_apply(txn); assert_eq!( @@ -78,14 +90,13 @@ fn freeze_unfreeze_account() { let mut executor = test_env.executor; let account = executor.create_raw_account(); - let blessed = test_env.tc_account; executor.execute_and_apply( blessed .transaction() .script(encode_create_parent_vasp_account_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, *account.address(), account.auth_key_prefix(), @@ -152,7 +163,7 @@ fn create_parent_and_child_vasp() { blessed .transaction() .script(encode_create_parent_vasp_account_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, *parent.address(), parent.auth_key_prefix(), @@ -168,7 +179,7 @@ fn create_parent_and_child_vasp() { parent .transaction() .script(encode_create_child_vasp_account_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *child.address(), child.auth_key_prefix(), add_all_currencies, @@ -180,9 +191,9 @@ fn create_parent_and_child_vasp() { // check for zero balance assert_eq!( executor - .read_balance_resource(&child, account::xus_currency_code()) + .read_balance_resource(&child) .unwrap() - .coin(), + .token(), 0 ); @@ -218,7 +229,7 @@ fn create_child_vasp_all_currencies() { blessed .transaction() .script(encode_create_parent_vasp_account_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, *parent.address(), parent.auth_key_prefix(), @@ -234,7 +245,7 @@ fn create_child_vasp_all_currencies() { executor.execute_and_apply( dd.transaction() .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *parent.address(), amount, vec![], @@ -245,7 +256,7 @@ fn create_child_vasp_all_currencies() { ); assert!(executor - .read_balance_resource(&parent, account::xus_currency_code()) + .read_balance_resource(&parent) .is_some()); // create a child VASP with a balance of amount @@ -253,7 +264,7 @@ fn create_child_vasp_all_currencies() { parent .transaction() .script(encode_create_child_vasp_account_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *child.address(), child.auth_key_prefix(), add_all_currencies, @@ -265,7 +276,7 @@ fn create_child_vasp_all_currencies() { ); assert!(executor - .read_balance_resource(&parent, account::xus_currency_code()) + .read_balance_resource(&parent) .is_some()); } } @@ -287,7 +298,7 @@ fn create_child_vasp_with_balance() { blessed .transaction() .script(encode_create_parent_vasp_account_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, *parent.address(), parent.auth_key_prefix(), @@ -303,7 +314,7 @@ fn create_child_vasp_with_balance() { executor.execute_and_apply( dd.transaction() .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *parent.address(), amount, vec![], @@ -315,9 +326,9 @@ fn create_child_vasp_with_balance() { assert_eq!( executor - .read_balance_resource(&parent, account::xus_currency_code()) + .read_balance_resource(&parent) .unwrap() - .coin(), + .token() as u64, amount ); @@ -326,7 +337,7 @@ fn create_child_vasp_with_balance() { parent .transaction() .script(encode_create_child_vasp_account_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *child.address(), child.auth_key_prefix(), add_all_currencies, @@ -340,9 +351,9 @@ fn create_child_vasp_with_balance() { // check balance assert_eq!( executor - .read_balance_resource(&child, account::xus_currency_code()) + .read_balance_resource(&child) .unwrap() - .coin(), + .token() as u64, amount ); } @@ -372,7 +383,7 @@ fn dual_attestation_payment() { blessed .transaction() .script(encode_create_parent_vasp_account_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, *payment_sender.address(), payment_sender.auth_key_prefix(), @@ -387,7 +398,7 @@ fn dual_attestation_payment() { blessed .transaction() .script(encode_create_parent_vasp_account_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, *payment_receiver.address(), payment_receiver.auth_key_prefix(), @@ -413,7 +424,7 @@ fn dual_attestation_payment() { executor.execute_and_apply( dd.transaction() .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *payment_sender.address(), XUS_THRESHOLD * 10, vec![], @@ -428,7 +439,7 @@ fn dual_attestation_payment() { payment_sender .transaction() .script(encode_create_child_vasp_account_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *sender_child.address(), sender_child.auth_key_prefix(), false, @@ -443,7 +454,7 @@ fn dual_attestation_payment() { payment_receiver .transaction() .script(encode_create_child_vasp_account_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *payee_child.address(), payee_child.auth_key_prefix(), false, @@ -464,7 +475,7 @@ fn dual_attestation_payment() { *payment_sender.address(), *payment_receiver.address(), payment_amount, - account_config::xus_tag(), + account_config::stc_type_tag(), ref_id, &receiver_vasp_compliance_private_key, )) @@ -486,7 +497,7 @@ fn dual_attestation_payment() { *payment_sender.address(), *payee_child.address(), payment_amount, - account_config::xus_tag(), + account_config::stc_type_tag(), ref_id, &receiver_vasp_compliance_private_key, )) @@ -503,7 +514,7 @@ fn dual_attestation_payment() { payment_sender .transaction() .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *payment_receiver.address(), payment_amount, ref_id, @@ -532,7 +543,7 @@ fn dual_attestation_payment() { *payment_sender.address(), *payment_receiver.address(), payment_amount, - account_config::xus_tag(), + account_config::stc_type_tag(), ref_id, // Sign with the wrong private key &sender_vasp_compliance_private_key, @@ -554,7 +565,7 @@ fn dual_attestation_payment() { *payment_sender.address(), *payment_receiver.address(), payment_amount, - account_config::xus_tag(), + account_config::stc_type_tag(), ref_id, &sender_vasp_compliance_private_key, )) @@ -571,7 +582,7 @@ fn dual_attestation_payment() { payment_sender .transaction() .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *sender_child.address(), payment_amount * 2, vec![0], @@ -586,7 +597,7 @@ fn dual_attestation_payment() { payment_sender .transaction() .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *sender_child.address(), payment_amount * 2, vec![0], @@ -604,7 +615,7 @@ fn dual_attestation_payment() { sender_child .transaction() .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *payment_sender.address(), payment_amount, vec![0], @@ -620,7 +631,7 @@ fn dual_attestation_payment() { sender_child .transaction() .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *sender_child.address(), payment_amount, vec![0], @@ -655,7 +666,7 @@ fn dual_attestation_payment() { *payment_sender.address(), *payment_receiver.address(), payment_amount, - account_config::xus_tag(), + account_config::stc_type_tag(), // pick an arbitrary ref_id bcs::to_bytes(&9999u64).unwrap(), &receiver_vasp_compliance_private_key, @@ -674,7 +685,7 @@ fn dual_attestation_payment() { *payment_receiver.address(), *payment_sender.address(), payment_amount, - account_config::xus_tag(), + account_config::stc_type_tag(), // pick an arbitrary ref_id bcs::to_bytes(&9999u64).unwrap(), &receiver_vasp_compliance_private_key, @@ -751,7 +762,7 @@ fn dd_dual_attestation_payments() { blessed .transaction() .script(encode_create_parent_vasp_account_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, *parent_vasp.address(), parent_vasp.auth_key_prefix(), @@ -766,7 +777,7 @@ fn dd_dual_attestation_payments() { blessed .transaction() .script(encode_create_designated_dealer_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, *dd1.address(), dd1.auth_key_prefix(), @@ -781,7 +792,7 @@ fn dd_dual_attestation_payments() { blessed .transaction() .script(encode_create_designated_dealer_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, *dd2.address(), dd2.auth_key_prefix(), @@ -827,7 +838,7 @@ fn dd_dual_attestation_payments() { mint_dd .transaction() .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *dd1.address(), XUS_THRESHOLD * 4, vec![], @@ -841,7 +852,7 @@ fn dd_dual_attestation_payments() { mint_dd .transaction() .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *parent_vasp.address(), XUS_THRESHOLD * 2, vec![], @@ -855,7 +866,7 @@ fn dd_dual_attestation_payments() { executor.execute_and_apply( dd1.transaction() .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *dd2.address(), XUS_THRESHOLD, vec![0], @@ -871,7 +882,7 @@ fn dd_dual_attestation_payments() { *dd1.address(), *dd2.address(), XUS_THRESHOLD, - account_config::xus_tag(), + account_config::stc_type_tag(), // pick an arbitrary ref_id bcs::to_bytes(&9999u64).unwrap(), &dd2_compliance_private_key, @@ -884,7 +895,7 @@ fn dd_dual_attestation_payments() { executor.execute_and_apply( dd1.transaction() .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *parent_vasp.address(), XUS_THRESHOLD, vec![0], @@ -900,7 +911,7 @@ fn dd_dual_attestation_payments() { *dd1.address(), *parent_vasp.address(), XUS_THRESHOLD, - account_config::xus_tag(), + account_config::stc_type_tag(), // pick an arbitrary ref_id bcs::to_bytes(&9999u64).unwrap(), &parent_vasp_compliance_private_key, @@ -914,7 +925,7 @@ fn dd_dual_attestation_payments() { parent_vasp .transaction() .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *dd1.address(), XUS_THRESHOLD, vec![0], @@ -931,7 +942,7 @@ fn dd_dual_attestation_payments() { *parent_vasp.address(), *dd1.address(), XUS_THRESHOLD, - account_config::xus_tag(), + account_config::stc_type_tag(), // pick an arbitrary ref_id bcs::to_bytes(&9999u64).unwrap(), &dd1_compliance_private_key, @@ -945,7 +956,7 @@ fn dd_dual_attestation_payments() { parent_vasp .transaction() .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *dd1.address(), XUS_THRESHOLD, vec![0], @@ -1032,7 +1043,7 @@ fn recovery_address() { blessed .transaction() .script(encode_create_parent_vasp_account_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, *parent.address(), parent.auth_key_prefix(), @@ -1048,7 +1059,7 @@ fn recovery_address() { parent .transaction() .script(encode_create_child_vasp_account_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *child.address(), child.auth_key_prefix(), add_all_currencies, @@ -1119,7 +1130,7 @@ fn recovery_address() { blessed .transaction() .script(encode_create_parent_vasp_account_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, *other_vasp.address(), other_vasp.auth_key_prefix(), @@ -1163,107 +1174,108 @@ fn recovery_address() { } } -#[test] -fn add_child_currencies() { - let mut executor = FakeExecutor::from_genesis_file(); - executor.set_golden_file(current_function_name!()); - - let vasp_a = executor.create_raw_account(); - let vasp_a_child1 = executor.create_raw_account(); - let vasp_b = executor.create_raw_account(); - let vasp_b_child1 = executor.create_raw_account(); - let vasp_b_child2 = executor.create_raw_account(); - let blessed = Account::new_blessed_tc(); - let dr_account = Account::new_starcoin_root(); - let tc_sequence_number = 0; - - currencies::add_currency_to_system(&mut executor, "COIN", &dr_account, 0); - - executor.execute_and_apply( - blessed - .transaction() - .script(encode_create_parent_vasp_account_script( - account_config::xus_tag(), - 0, - *vasp_a.address(), - vasp_a.auth_key_prefix(), - vec![], - false, - )) - .sequence_number(tc_sequence_number) - .sign(), - ); - - // Adding a child with the same currency is no issue - executor.execute_and_apply( - vasp_a - .transaction() - .script(encode_create_child_vasp_account_script( - account_config::xus_tag(), - *vasp_a_child1.address(), - vasp_a_child1.auth_key_prefix(), - false, - 0, - )) - .sequence_number(0) - .sign(), - ); - - executor.execute_and_apply( - vasp_a - .transaction() - .script(encode_add_currency_to_account_script( - account_config::type_tag_for_currency_code(account::currency_code("COIN")), - )) - .sequence_number(1) - .sign(), - ); - - /////////////////////////////////////////////////////////////////////////// - // Now make a parent with all currencies, and make sure the children are fine - /////////////////////////////////////////////////////////////////////////// - - executor.execute_and_apply( - blessed - .transaction() - .script(encode_create_parent_vasp_account_script( - account_config::xus_tag(), - 0, - *vasp_b.address(), - vasp_b.auth_key_prefix(), - vec![], - true, - )) - .sequence_number(tc_sequence_number.checked_add(1).unwrap()) - .sign(), - ); - - // Adding a child with the same currency and all other currencies isn't an issue - executor.execute_and_apply( - vasp_b - .transaction() - .script(encode_create_child_vasp_account_script( - account_config::xus_tag(), - *vasp_b_child1.address(), - vasp_b_child1.auth_key_prefix(), - true, - 0, - )) - .sequence_number(0) - .sign(), - ); - // Adding a child with a different currency than the parent VASP is OK - executor.execute_and_apply( - vasp_b - .transaction() - .script(encode_create_child_vasp_account_script( - account_config::type_tag_for_currency_code(account::currency_code("COIN")), - *vasp_b_child2.address(), - vasp_b_child2.auth_key_prefix(), - false, - 0, - )) - .sequence_number(1) - .sign(), - ); -} +// TODO(bob): starcoin e2e-test not support +//#[test] +// fn add_child_currencies() { +// let mut executor = FakeExecutor::from_genesis_file(); +// executor.set_golden_file(current_function_name!()); +// +// let vasp_a = executor.create_raw_account(); +// let vasp_a_child1 = executor.create_raw_account(); +// let vasp_b = executor.create_raw_account(); +// let vasp_b_child1 = executor.create_raw_account(); +// let vasp_b_child2 = executor.create_raw_account(); +// let blessed = Account::new_blessed_tc(); +// let dr_account = Account::new_starcoin_root(); +// let tc_sequence_number = 0; +// +// currencies::add_currency_to_system(&mut executor, "COIN", &dr_account, 0); +// +// executor.execute_and_apply( +// blessed +// .transaction() +// .script(encode_create_parent_vasp_account_script( +// account_config::stc_type_tag(), +// 0, +// *vasp_a.address(), +// vasp_a.auth_key_prefix(), +// vec![], +// false, +// )) +// .sequence_number(tc_sequence_number) +// .sign(), +// ); +// +// // Adding a child with the same currency is no issue +// executor.execute_and_apply( +// vasp_a +// .transaction() +// .script(encode_create_child_vasp_account_script( +// account_config::stc_type_tag(), +// *vasp_a_child1.address(), +// vasp_a_child1.auth_key_prefix(), +// false, +// 0, +// )) +// .sequence_number(0) +// .sign(), +// ); +// +// executor.execute_and_apply( +// vasp_a +// .transaction() +// .script(encode_add_currency_to_account_script( +// account_config::type_tag_for_currency_code(account::currency_code("COIN")), +// )) +// .sequence_number(1) +// .sign(), +// ); +// +// /////////////////////////////////////////////////////////////////////////// +// // Now make a parent with all currencies, and make sure the children are fine +// /////////////////////////////////////////////////////////////////////////// +// +// executor.execute_and_apply( +// blessed +// .transaction() +// .script(encode_create_parent_vasp_account_script( +// account_config::stc_type_tag(), +// 0, +// *vasp_b.address(), +// vasp_b.auth_key_prefix(), +// vec![], +// true, +// )) +// .sequence_number(tc_sequence_number.checked_add(1).unwrap()) +// .sign(), +// ); +// +// // Adding a child with the same currency and all other currencies isn't an issue +// executor.execute_and_apply( +// vasp_b +// .transaction() +// .script(encode_create_child_vasp_account_script( +// account_config::stc_type_tag(), +// *vasp_b_child1.address(), +// vasp_b_child1.auth_key_prefix(), +// true, +// 0, +// )) +// .sequence_number(0) +// .sign(), +// ); +// // Adding a child with a different currency than the parent VASP is OK +// executor.execute_and_apply( +// vasp_b +// .transaction() +// .script(encode_create_child_vasp_account_script( +// account_config::type_tag_for_currency_code(account::currency_code("COIN")), +// *vasp_b_child2.address(), +// vasp_b_child2.auth_key_prefix(), +// false, +// 0, +// )) +// .sequence_number(1) +// .sign(), +// ); +// } diff --git a/vm/e2e-testsuite/src/tests/transaction_fees.rs b/vm/e2e-testsuite/src/tests/transaction_fees.rs index 0ac7e08932..803dd14c7d 100644 --- a/vm/e2e-testsuite/src/tests/transaction_fees.rs +++ b/vm/e2e-testsuite/src/tests/transaction_fees.rs @@ -1,22 +1,21 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_framework_releases::legacy::transaction_scripts::LegacyStdlibScript; -use diem_transaction_builder::stdlib::*; -use diem_types::{ - account_config::{self, BurnEvent, XUS_NAME}, - transaction::{authenticator::AuthenticationKey, Script, TransactionArgument}, - vm_status::KeptVMStatus, +use move_core_types::identifier::Identifier; +use move_core_types::language_storage::{StructTag, TypeTag}; +use crate::tests::fake_stdlib::{ + encode_burn_txn_fees_script, encode_create_parent_vasp_account_script, + encode_peer_to_peer_with_metadata_script, }; -use move_core_types::{ - identifier::Identifier, - language_storage::{StructTag, TypeTag}, -}; -use starcoin_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, Uniform}; -use starcoin_language_e2e_tests::{ - test_with_different_versions, versioning::CURRENT_RELEASE_VERSIONS, -}; -use std::convert::TryFrom; +use move_core_types::transaction_argument::TransactionArgument; +use move_core_types::vm_status::KeptVMStatus; +use starcoin_crypto::ed25519::Ed25519PrivateKey; +use starcoin_crypto::{PrivateKey, Uniform}; +use starcoin_language_e2e_tests::test_with_different_versions; +use starcoin_language_e2e_tests::versioning::CURRENT_RELEASE_VERSIONS; +use starcoin_vm_types::account_config; +use starcoin_vm_types::account_config::BurnEvent; +use starcoin_vm_types::transaction::authenticator::AuthenticationKey; #[test] fn burn_txn_fees() { @@ -31,7 +30,7 @@ fn burn_txn_fees() { blessed .transaction() .script(encode_create_parent_vasp_account_script( - account_config::xus_tag(), + account_config::stc_type_tag(), 0, *sender.address(), sender.auth_key_prefix(), @@ -45,7 +44,7 @@ fn burn_txn_fees() { executor.execute_and_apply( dd.transaction() .script(encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *sender.address(), 10_000_000, vec![], @@ -79,12 +78,12 @@ fn burn_txn_fees() { status.gas_used() }; - let xus_ty = TypeTag::Struct(StructTag { + let xus_ty = TypeTag::Struct(Box::new(StructTag { address: account_config::CORE_CODE_ADDRESS, module: Identifier::new("XUS").unwrap(), name: Identifier::new("XUS").unwrap(), type_params: vec![], - }); + })); let output = executor.execute_and_apply( blessed diff --git a/vm/e2e-testsuite/src/tests/transaction_fuzzer.rs b/vm/e2e-testsuite/src/tests/transaction_fuzzer.rs index aacea08076..f565319707 100644 --- a/vm/e2e-testsuite/src/tests/transaction_fuzzer.rs +++ b/vm/e2e-testsuite/src/tests/transaction_fuzzer.rs @@ -1,14 +1,12 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_framework_releases::legacy::transaction_scripts::LegacyStdlibScript; -use diem_transaction_builder::stdlib::{encode_create_parent_vasp_account_script, ScriptCall}; -use diem_types::account_config; use proptest::{collection::vec, prelude::*}; use starcoin_language_e2e_tests::{ account::{self, Account}, executor::FakeExecutor, }; +use starcoin_types::account_config; use std::convert::TryFrom; proptest! { diff --git a/vm/e2e-testsuite/src/tests/validator_set_management.rs b/vm/e2e-testsuite/src/tests/validator_set_management.rs index 3dad837aaf..ded50c4853 100644 --- a/vm/e2e-testsuite/src/tests/validator_set_management.rs +++ b/vm/e2e-testsuite/src/tests/validator_set_management.rs @@ -1,16 +1,23 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_types::{ - on_chain_config::{new_epoch_event_key, VMPublishingOption}, - transaction::{TransactionOutput, TransactionStatus, WriteSetPayload}, - vm_status::KeptVMStatus, -}; use starcoin_language_e2e_tests::{ account::Account, current_function_name, executor::FakeExecutor, test_with_different_versions, versioning::CURRENT_RELEASE_VERSIONS, }; -use starcoin_transaction_builder::stdlib::*; + +use starcoin_vm_types::{ + on_chain_config::new_epoch_event_key, + transaction::{TransactionOutput, TransactionStatus}, + vm_status::KeptVMStatus, +}; + +use crate::tests::fake_stdlib::{ + encode_add_validator_and_reconfigure_script, encode_create_validator_account_script, + encode_create_validator_operator_account_script, encode_register_validator_config_script, + encode_set_validator_config_and_reconfigure_script, encode_set_validator_operator_script, + encode_set_validator_operator_with_nonce_admin_script, +}; fn assert_aborted_with(output: TransactionOutput, error_code: u64) { assert!(matches!( @@ -117,12 +124,12 @@ fn validator_add() { #[test] fn validator_add_max_number() { - let mut executor = FakeExecutor::custom_genesis( - diem_framework_releases::current_module_blobs(), - Some(256), - VMPublishingOption::open(), - ); - + // let mut executor = FakeExecutor::custom_genesis( + // diem_framework_releases::current_module_blobs(), + // Some(256), + // VMPublishingOption::open(), + // ); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); let output = try_add_validator(&mut executor, &Account::new_starcoin_root(), 0); @@ -324,17 +331,17 @@ fn validator_set_operator_set_key_reconfigure() { b"operator_1".to_vec(), *operator_account_1.address(), ); - let txn = diem_root_account - .transaction() - .write_set(WriteSetPayload::Script { - script: admin_script, - execute_as: *validator_account.address(), - }) + let txn = diem_root_account.transaction() + //.script(WriteSetPayload::Script { + // script: admin_script, + // execute_as: *validator_account.address(), + // }) + .script(admin_script) .sequence_number(test_env.dr_sequence_number.checked_add(3).unwrap()) .sign(); executor.new_block(); - let output = executor.execute_transaction(txn); + let output = executor.execute_transaction(txn); assert_eq!( output.status(), &TransactionStatus::Keep(KeptVMStatus::Executed) diff --git a/vm/e2e-testsuite/src/tests/vasps.rs b/vm/e2e-testsuite/src/tests/vasps.rs deleted file mode 100644 index 0f2e634413..0000000000 --- a/vm/e2e-testsuite/src/tests/vasps.rs +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// SPDX-License-Identifier: Apache-2.0 - -#![forbid(unsafe_code)] - -use diem_transaction_builder::stdlib::*; -use diem_types::{ - account_config, - transaction::{authenticator::AuthenticationKey, TransactionStatus}, - vm_status::KeptVMStatus, -}; -use move_core_types::{ - value::{serialize_values, MoveValue}, - vm_status::VMStatus, -}; -use starcoin_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, Uniform}; -use starcoin_language_e2e_tests::{ - test_with_different_versions, versioning::CURRENT_RELEASE_VERSIONS, -}; - -#[test] -fn valid_creator_already_vasp() { - test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { - let mut executor = test_env.executor; - - let account = executor.create_raw_account(); - - let treasury_compliance = test_env.tc_account; - - executor.execute_and_apply( - treasury_compliance - .transaction() - .script(encode_create_parent_vasp_account_script( - account_config::xus_tag(), - 0, - *account.address(), - account.auth_key_prefix(), - vec![], - true, - )) - .sequence_number(test_env.tc_sequence_number) - .sign(), - ); - - let err = executor - .try_exec( - "VASP", - "publish_parent_vasp_credential", - vec![], - serialize_values(&vec![ - MoveValue::Signer(*account.address()), - MoveValue::Signer(*treasury_compliance.address()), - ]), - ) - .unwrap_err(); - if let VMStatus::MoveAbort(_, code) = err { - assert_eq!(code, 6); - } else { - panic!("expected MoveAbort") - } - } - } -} - -#[test] -fn max_child_accounts_for_vasp_recovery_address() { - let max_num_child_accounts = 256; - - test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { - let mut executor = test_env.executor; - - let account = executor.create_raw_account(); - - let treasury_compliance = test_env.tc_account; - - executor.execute_and_apply( - treasury_compliance - .transaction() - .script(encode_create_parent_vasp_account_script( - account_config::xus_tag(), - 0, - *account.address(), - account.auth_key_prefix(), - vec![], - true, - )) - .sequence_number(test_env.tc_sequence_number) - .sign(), - ); - - let mut accounts = Vec::new(); - - // Batch the transactions to reduce the runtime of the test (cuts ~100 seconds) - let mut block = Vec::new(); - // Create the maximum number of allowed child accounts - for i in 0..max_num_child_accounts + 1 { - let child = executor.create_raw_account(); - accounts.push(child.clone()); - block.push( - account - .transaction() - .script(encode_create_child_vasp_account_script( - account_config::xus_tag(), - *child.address(), - child.auth_key_prefix(), - false, - 0, - )) - .sequence_number(i) - .sign(), - ); - } - - let output = executor.execute_block(block).unwrap(); - for output in output { - executor.apply_write_set(output.write_set()) - } - - // Now setup the recovery addresses - let recovery_account = accounts.remove(0); - let one_account_too_many = accounts.remove(0); - executor.execute_and_apply( - recovery_account - .transaction() - .script(encode_create_recovery_address_script()) - .sequence_number(0) - .sign(), - ); - - // Batch the transactions to reduce the runtime of the test (cuts ~ another 100 seconds) - let block = accounts - .iter() - .map(|account| { - account - .transaction() - .script(encode_add_recovery_rotation_capability_script( - *recovery_account.address(), - )) - .sequence_number(0) - .sign() - }) - .collect(); - - let outputs = executor.execute_block(block).unwrap(); - - for output in outputs { - executor.apply_write_set(output.write_set()) - } - - // Make sure that we can't add any more - let output = executor.execute_transaction( - one_account_too_many - .transaction() - .script(encode_add_recovery_rotation_capability_script( - *recovery_account.address(), - )) - .sequence_number(0) - .sign(), - ); - - if let Ok(KeptVMStatus::MoveAbort(_, code)) = output.status().status() { - assert_eq!(code, 1544); - } else { - panic!("expected MoveAbort") - } - - // Batch again, cuts about ~100 seconds more as well - let block = accounts - .iter() - .map(|account| { - let privkey = Ed25519PrivateKey::generate_for_testing(); - let pubkey = privkey.public_key(); - let new_key_hash = AuthenticationKey::ed25519(&pubkey).to_vec(); - account - .transaction() - .script( - encode_rotate_authentication_key_with_recovery_address_script( - *recovery_account.address(), - *account.address(), - new_key_hash, - ), - ) - .sequence_number(1) - .sign() - }) - .collect(); - - let outputs = executor.execute_block(block).unwrap(); - - // Now make sure all the rotations were executed - for output in outputs { - assert!(*output.status() == TransactionStatus::Keep(KeptVMStatus::Executed)); - } - } - } -} diff --git a/vm/e2e-testsuite/src/tests/verify_txn.rs b/vm/e2e-testsuite/src/tests/verify_txn.rs index 22054a18e8..3ad0cb7843 100644 --- a/vm/e2e-testsuite/src/tests/verify_txn.rs +++ b/vm/e2e-testsuite/src/tests/verify_txn.rs @@ -2,26 +2,56 @@ // SPDX-License-Identifier: Apache-2.0 use move_binary_format::CompiledModule; -use move_core_types::account_address::AccountAddress; +use move_core_types::transaction_argument::TransactionArgument; +use move_core_types::{ + account_address::AccountAddress, + identifier::Identifier, + language_storage::{StructTag, TypeTag}, + value::{serialize_values, MoveValue}, + vm_status::{KeptVMStatus, StatusCode}, +}; use move_ir_compiler::Compiler; -use starcoin_crypto::ed25519::Ed25519PrivateKey; -use starcoin_crypto::Uniform; -use starcoin_language_e2e_tests::account::Account; -use starcoin_language_e2e_tests::executor::FakeExecutor; +use starcoin_crypto::{ed25519::Ed25519PrivateKey, keygen::KeyGen, PrivateKey, Uniform}; + use starcoin_language_e2e_tests::{ - assert_prologue_parity, current_function_name, test_with_different_versions, + account::Account, + assert_prologue_parity, + compile::compile_module, + //assert_prologue_disparity, + current_function_name, + executor::FakeExecutor, + gas_costs, + test_with_different_versions, + transaction_status_eq, + versioning::CURRENT_RELEASE_VERSIONS, +}; +use starcoin_transaction_builder::{stdlib_compiled_modules, StdLibOptions}; +use starcoin_types::{account_config, transaction}; +use starcoin_vm_types::gas_schedule::G_TEST_GAS_CONSTANTS; +use starcoin_vm_types::genesis_config::ChainId; +use starcoin_vm_types::genesis_config::StdlibVersion::Latest; +use starcoin_vm_types::{ + account_config::{stc_type_tag, STC_TOKEN_CODE_STR}, + transaction::TransactionPayload, }; +use starcoin_vm_types::{ + test_helpers::transaction_test_helpers, + transaction::{Script, TransactionStatus}, +}; + +use crate::tests::fake_stdlib::{self, encode_peer_to_peer_with_metadata_script}; #[test] fn verify_signature() { test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { let mut executor = test_env.executor; + // let executor = FakeExecutor::from_test_genesis(); let sender = executor.create_raw_account_data(900_000, 10); executor.add_account_data(&sender); // Generate a new key pair to try and sign things with. let private_key = Ed25519PrivateKey::generate_for_testing(); let program = encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *sender.address(), 100, vec![], @@ -31,12 +61,12 @@ fn verify_signature() { *sender.address(), 0, &private_key, - sender.account().pubkey.clone(), + sender.account().public_key().clone(), Some(program), ); assert_prologue_parity!( - executor.verify_transaction(signed_txn.clone()).status(), + executor.verify_transaction(signed_txn.clone()).unwrap().status_code(), executor.execute_transaction(signed_txn).status(), StatusCode::INVALID_SIGNATURE ); @@ -44,334 +74,338 @@ fn verify_signature() { } } -#[test] -fn verify_multi_agent() { - let mut executor = FakeExecutor::from_genesis_file(); - executor.set_golden_file(current_function_name!()); - let sender = executor.create_raw_account_data(1_000_010, 10); - let secondary_signer = executor.create_raw_account_data(100_100, 100); - - executor.add_account_data(&sender); - executor.add_account_data(&secondary_signer); - - let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( - *sender.address(), - vec![*secondary_signer.address()], - 10, - &sender.account().privkey, - sender.account().pubkey.clone(), - vec![&secondary_signer.account().privkey], - vec![secondary_signer.account().pubkey.clone()], - Some(multi_agent_swap_script(10, 10)), - ); - assert_eq!(executor.verify_transaction(signed_txn).status(), None); -} - -#[test] -fn verify_multi_agent_multiple_secondary_signers() { - let mut executor = FakeExecutor::from_genesis_file(); - executor.set_golden_file(current_function_name!()); - let sender = executor.create_raw_account_data(1_000_010, 10); - let secondary_signer = executor.create_raw_account_data(100_100, 100); - let third_signer = executor.create_raw_account_data(100_100, 100); - - executor.add_account_data(&sender); - executor.add_account_data(&secondary_signer); - executor.add_account_data(&third_signer); - - let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( - *sender.address(), - vec![*secondary_signer.address(), *third_signer.address()], - 10, - &sender.account().privkey, - sender.account().pubkey.clone(), - vec![ - &secondary_signer.account().privkey, - &third_signer.account().privkey, - ], - vec![ - secondary_signer.account().pubkey.clone(), - third_signer.account().pubkey.clone(), - ], - Some(multi_agent_mint_script(100, 0)), - ); - assert_eq!(executor.verify_transaction(signed_txn).status(), None); -} - -#[test] -fn verify_multi_agent_invalid_sender_signature() { - let mut executor = FakeExecutor::from_genesis_file(); - executor.set_golden_file(current_function_name!()); - - let sender = executor.create_raw_account_data(1_000_010, 10); - let secondary_signer = executor.create_raw_account_data(100_100, 100); - - executor.add_account_data(&sender); - executor.add_account_data(&secondary_signer); - - let private_key = Ed25519PrivateKey::generate_for_testing(); - - // Sign using the wrong key for the sender, and correct key for the secondary signer. - let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( - *sender.address(), - vec![*secondary_signer.address()], - 10, - &private_key, - sender.account().pubkey.clone(), - vec![&secondary_signer.account().privkey], - vec![secondary_signer.account().pubkey.clone()], - None, - ); - assert_prologue_parity!( - executor.verify_transaction(signed_txn.clone()).status(), - executor.execute_transaction(signed_txn).status(), - StatusCode::INVALID_SIGNATURE - ); -} - -#[test] -fn verify_multi_agent_invalid_secondary_signature() { - let mut executor = FakeExecutor::from_genesis_file(); - executor.set_golden_file(current_function_name!()); - let sender = executor.create_raw_account_data(1_000_010, 10); - let secondary_signer = executor.create_raw_account_data(100_100, 100); - - executor.add_account_data(&sender); - executor.add_account_data(&secondary_signer); - - let private_key = Ed25519PrivateKey::generate_for_testing(); - - // Sign using the correct keys for the sender, but wrong keys for the secondary signer. - let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( - *sender.address(), - vec![*secondary_signer.address()], - 10, - &sender.account().privkey, - sender.account().pubkey.clone(), - vec![&private_key], - vec![secondary_signer.account().pubkey.clone()], - None, - ); - assert_prologue_parity!( - executor.verify_transaction(signed_txn.clone()).status(), - executor.execute_transaction(signed_txn).status(), - StatusCode::INVALID_SIGNATURE - ); -} - -#[test] -fn verify_multi_agent_num_sigs_exceeds() { - let mut executor = FakeExecutor::from_genesis_file(); - executor.set_golden_file(current_function_name!()); - let mut sender_seq_num = 10; - let secondary_signer_seq_num = 100; - let sender = executor.create_raw_account_data(1_000_010, sender_seq_num); - let secondary_signer = executor.create_raw_account_data(100_100, secondary_signer_seq_num); - - executor.add_account_data(&sender); - executor.add_account_data(&secondary_signer); - - // create two multisigs with `MAX_NUM_OF_SIGS/MAX_NUM_OF_SIGS` policy. - let mut keygen = KeyGen::from_seed([9u8; 32]); - let threshold = MAX_NUM_OF_SIGS as u8; - - let (sender_privkeys, sender_pubkeys): (Vec, Vec) = - (0..threshold).map(|_| keygen.generate_keypair()).unzip(); - let sender_multi_ed_public_key = MultiEd25519PublicKey::new(sender_pubkeys, threshold).unwrap(); - let sender_new_auth_key = AuthenticationKey::multi_ed25519(&sender_multi_ed_public_key); - - let (secondary_signer_privkeys, secondary_signer_pubkeys) = - (0..threshold).map(|_| keygen.generate_keypair()).unzip(); - let secondary_signer_multi_ed_public_key = - MultiEd25519PublicKey::new(secondary_signer_pubkeys, threshold).unwrap(); - let secondary_signer_new_auth_key = - AuthenticationKey::multi_ed25519(&secondary_signer_multi_ed_public_key); - - // (1) rotate keys to multisigs - let sender_output = &executor.execute_transaction(rotate_key_txn( - sender.account(), - sender_new_auth_key.to_vec(), - sender_seq_num, - )); - assert_eq!( - sender_output.status(), - &TransactionStatus::Keep(KeptVMStatus::Executed), - ); - executor.apply_write_set(sender_output.write_set()); - sender_seq_num += 1; - - let secondary_signer_output = &executor.execute_transaction(rotate_key_txn( - secondary_signer.account(), - secondary_signer_new_auth_key.to_vec(), - secondary_signer_seq_num, - )); - assert_eq!( - secondary_signer_output.status(), - &TransactionStatus::Keep(KeptVMStatus::Executed), - ); - executor.apply_write_set(secondary_signer_output.write_set()); - - // (2) sign a txn with new multisig private keys - let txn = raw_multi_agent_swap_txn( - sender.account(), - secondary_signer.account(), - sender_seq_num, - 0, - 0, - ); - let raw_txn_with_data = - RawTransactionWithData::new_multi_agent(txn.clone(), vec![*secondary_signer.address()]); - let sender_sig = MultiEd25519PrivateKey::new(sender_privkeys, threshold) - .unwrap() - .sign(&raw_txn_with_data); - let secondary_signer_sig = MultiEd25519PrivateKey::new(secondary_signer_privkeys, threshold) - .unwrap() - .sign(&raw_txn_with_data); - let signed_txn = SignedTransaction::new_multi_agent( - txn, - AccountAuthenticator::multi_ed25519(sender_multi_ed_public_key, sender_sig), - vec![*secondary_signer.address()], - vec![AccountAuthenticator::multi_ed25519( - secondary_signer_multi_ed_public_key, - secondary_signer_sig, - )], - ); - - // Transaction will fail validation because the number of signatures exceeds the maximum number - // of signatures allowed. - assert_prologue_parity!( - executor.verify_transaction(signed_txn.clone()).status(), - executor.execute_transaction(signed_txn).status(), - StatusCode::INVALID_SIGNATURE - ); -} - -#[test] -fn verify_multi_agent_wrong_number_of_signer() { - let mut executor = FakeExecutor::from_genesis_file(); - executor.set_golden_file(current_function_name!()); - let sender = executor.create_raw_account_data(1_000_010, 10); - let secondary_signer = executor.create_raw_account_data(100_100, 100); - let third_signer = executor.create_raw_account_data(100_100, 100); - - executor.add_account_data(&sender); - executor.add_account_data(&secondary_signer); - executor.add_account_data(&third_signer); - - // Number of secondary signers according is 2 but we only - // include the signature of one of the secondary signers. - let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( - *sender.address(), - vec![*secondary_signer.address(), *third_signer.address()], - 10, - &sender.account().privkey, - sender.account().pubkey.clone(), - vec![&secondary_signer.account().privkey], - vec![secondary_signer.account().pubkey.clone()], - Some(multi_agent_mint_script(10, 0)), - ); - assert_prologue_parity!( - executor.verify_transaction(signed_txn.clone()).status(), - executor.execute_transaction(signed_txn).status(), - StatusCode::SECONDARY_KEYS_ADDRESSES_COUNT_MISMATCH - ); -} - -#[test] -fn verify_multi_agent_duplicate_sender() { - let mut executor = FakeExecutor::from_genesis_file(); - executor.set_golden_file(current_function_name!()); - let sender = executor.create_raw_account_data(1_000_010, 10); - let secondary_signer = executor.create_raw_account_data(100_100, 100); - - executor.add_account_data(&sender); - executor.add_account_data(&secondary_signer); - // Duplicates in signers: sender and secondary signer have the same address. - let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( - *sender.address(), - vec![*sender.address()], - 10, - &sender.account().privkey, - sender.account().pubkey.clone(), - vec![&sender.account().privkey], - vec![sender.account().pubkey.clone()], - Some(multi_agent_swap_script(10, 10)), - ); - assert_prologue_parity!( - executor.verify_transaction(signed_txn.clone()).status(), - executor.execute_transaction(signed_txn).status(), - StatusCode::SIGNERS_CONTAIN_DUPLICATES - ); -} - -#[test] -fn verify_multi_agent_duplicate_secondary_signer() { - let mut executor = FakeExecutor::from_genesis_file(); - executor.set_golden_file(current_function_name!()); - let sender = executor.create_raw_account_data(1_000_010, 10); - let secondary_signer = executor.create_raw_account_data(100_100, 100); - let third_signer = executor.create_raw_account_data(100_100, 100); - - executor.add_account_data(&sender); - executor.add_account_data(&secondary_signer); - executor.add_account_data(&third_signer); - - // Duplicates in secondary signers. - let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( - *sender.address(), - vec![ - *secondary_signer.address(), - *third_signer.address(), - *secondary_signer.address(), - ], - 10, - &sender.account().privkey, - sender.account().pubkey.clone(), - vec![ - &secondary_signer.account().privkey, - &third_signer.account().privkey, - &secondary_signer.account().privkey, - ], - vec![ - secondary_signer.account().pubkey.clone(), - third_signer.account().pubkey.clone(), - secondary_signer.account().pubkey.clone(), - ], - None, - ); - assert_prologue_parity!( - executor.verify_transaction(signed_txn.clone()).status(), - executor.execute_transaction(signed_txn).status(), - StatusCode::SIGNERS_CONTAIN_DUPLICATES - ); -} - -#[test] -fn verify_multi_agent_nonexistent_secondary_signer() { - let mut executor = FakeExecutor::from_genesis_file(); - executor.set_golden_file(current_function_name!()); - let sender = executor.create_raw_account_data(1_000_010, 10); - let secondary_signer = executor.create_raw_account_data(100_100, 100); - - executor.add_account_data(&sender); - - // Duplicates in signers: sender and secondary signer have the same address. - let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( - *sender.address(), - vec![*secondary_signer.address()], - 10, - &sender.account().privkey, - sender.account().pubkey.clone(), - vec![&secondary_signer.account().privkey], - vec![secondary_signer.account().pubkey.clone()], - Some(multi_agent_swap_script(10, 10)), - ); - assert_prologue_parity!( - executor.verify_transaction(signed_txn.clone()).status(), - executor.execute_transaction(signed_txn).status(), - StatusCode::SENDING_ACCOUNT_DOES_NOT_EXIST - ); -} +// TODO(BobOng):No support multi-agent +// #[test] +// fn verify_multi_agent() { +// let mut executor = FakeExecutor::from_genesis_file(); +// executor.set_golden_file(current_function_name!()); +// let sender = executor.create_raw_account_data(1_000_010, 10); +// let secondary_signer = executor.create_raw_account_data(100_100, 100); +// +// executor.add_account_data(&sender); +// executor.add_account_data(&secondary_signer); +// +// let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( +// *sender.address(), +// vec![*secondary_signer.address()], +// 10, +// &sender.account().privkey, +// sender.account().pubkey.clone(), +// vec![&secondary_signer.account().privkey], +// vec![secondary_signer.account().pubkey.clone()], +// Some(multi_agent_swap_script(10, 10)), +// ); +// assert_eq!(executor.verify_transaction(signed_txn).status(), None); +// } + +// TODO(BobOng):No support multi-agent +// #[test] +// fn verify_multi_agent_multiple_secondary_signers() { +// let mut executor = FakeExecutor::from_genesis_file(); +// executor.set_golden_file(current_function_name!()); +// let sender = executor.create_raw_account_data(1_000_010, 10); +// let secondary_signer = executor.create_raw_account_data(100_100, 100); +// let third_signer = executor.create_raw_account_data(100_100, 100); +// +// executor.add_account_data(&sender); +// executor.add_account_data(&secondary_signer); +// executor.add_account_data(&third_signer); +// +// let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( +// *sender.address(), +// vec![*secondary_signer.address(), *third_signer.address()], +// 10, +// &sender.account().privkey, +// sender.account().pubkey.clone(), +// vec![ +// &secondary_signer.account().privkey, +// &third_signer.account().privkey, +// ], +// vec![ +// secondary_signer.account().pubkey.clone(), +// third_signer.account().pubkey.clone(), +// ], +// Some(multi_agent_mint_script(100, 0)), +// ); +// assert_eq!(executor.verify_transaction(signed_txn).status(), None); +// } + +// TODO(BobOng):No support multi-agent +//#[test] +// fn verify_multi_agent_invalid_sender_signature() { +// let mut executor = FakeExecutor::from_genesis_file(); +// executor.set_golden_file(current_function_name!()); +// +// let sender = executor.create_raw_account_data(1_000_010, 10); +// let secondary_signer = executor.create_raw_account_data(100_100, 100); +// +// executor.add_account_data(&sender); +// executor.add_account_data(&secondary_signer); +// +// let private_key = Ed25519PrivateKey::generate_for_testing(); +// +// // Sign using the wrong key for the sender, and correct key for the secondary signer. +// let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( +// *sender.address(), +// vec![*secondary_signer.address()], +// 10, +// &private_key, +// sender.account().pubkey.clone(), +// vec![&secondary_signer.account().privkey], +// vec![secondary_signer.account().pubkey.clone()], +// None, +// ); +// assert_prologue_parity!( +// executor.verify_transaction(signed_txn.clone()).status(), +// executor.execute_transaction(signed_txn).status(), +// StatusCode::INVALID_SIGNATURE +// ); +// } + +// TODO(BobOng):No support multi-agent +// #[test] +// fn verify_multi_agent_invalid_secondary_signature() { +// let mut executor = FakeExecutor::from_genesis_file(); +// executor.set_golden_file(current_function_name!()); +// let sender = executor.create_raw_account_data(1_000_010, 10); +// let secondary_signer = executor.create_raw_account_data(100_100, 100); +// +// executor.add_account_data(&sender); +// executor.add_account_data(&secondary_signer); +// +// let private_key = Ed25519PrivateKey::generate_for_testing(); +// +// // Sign using the correct keys for the sender, but wrong keys for the secondary signer. +// let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( +// *sender.address(), +// vec![*secondary_signer.address()], +// 10, +// &sender.account().privkey, +// sender.account().pubkey.clone(), +// vec![&private_key], +// vec![secondary_signer.account().pubkey.clone()], +// None, +// ); +// assert_prologue_parity!( +// executor.verify_transaction(signed_txn.clone()).status(), +// executor.execute_transaction(signed_txn).status(), +// StatusCode::INVALID_SIGNATURE +// ); +// } +// +// #[test] +// fn verify_multi_agent_num_sigs_exceeds() { +// let mut executor = FakeExecutor::from_genesis_file(); +// executor.set_golden_file(current_function_name!()); +// let mut sender_seq_num = 10; +// let secondary_signer_seq_num = 100; +// let sender = executor.create_raw_account_data(1_000_010, sender_seq_num); +// let secondary_signer = executor.create_raw_account_data(100_100, secondary_signer_seq_num); +// +// executor.add_account_data(&sender); +// executor.add_account_data(&secondary_signer); +// +// // create two multisigs with `MAX_NUM_OF_SIGS/MAX_NUM_OF_SIGS` policy. +// let mut keygen = KeyGen::from_seed([9u8; 32]); +// let threshold = MAX_NUM_OF_SIGS as u8; +// +// let (sender_privkeys, sender_pubkeys): (Vec, Vec) = +// (0..threshold).map(|_| keygen.generate_keypair()).unzip(); +// let sender_multi_ed_public_key = MultiEd25519PublicKey::new(sender_pubkeys, threshold).unwrap(); +// let sender_new_auth_key = AuthenticationKey::multi_ed25519(&sender_multi_ed_public_key); +// +// let (secondary_signer_privkeys, secondary_signer_pubkeys) = +// (0..threshold).map(|_| keygen.generate_keypair()).unzip(); +// let secondary_signer_multi_ed_public_key = +// MultiEd25519PublicKey::new(secondary_signer_pubkeys, threshold).unwrap(); +// let secondary_signer_new_auth_key = +// AuthenticationKey::multi_ed25519(&secondary_signer_multi_ed_public_key); +// +// // (1) rotate keys to multisigs +// let sender_output = &executor.execute_transaction(rotate_key_txn( +// sender.account(), +// sender_new_auth_key.to_vec(), +// sender_seq_num, +// )); +// assert_eq!( +// sender_output.status(), +// &TransactionStatus::Keep(KeptVMStatus::Executed), +// ); +// executor.apply_write_set(sender_output.write_set()); +// sender_seq_num += 1; +// +// let secondary_signer_output = &executor.execute_transaction(rotate_key_txn( +// secondary_signer.account(), +// secondary_signer_new_auth_key.to_vec(), +// secondary_signer_seq_num, +// )); +// assert_eq!( +// secondary_signer_output.status(), +// &TransactionStatus::Keep(KeptVMStatus::Executed), +// ); +// executor.apply_write_set(secondary_signer_output.write_set()); +// +// // (2) sign a txn with new multisig private keys +// let txn = raw_multi_agent_swap_txn( +// sender.account(), +// secondary_signer.account(), +// sender_seq_num, +// 0, +// 0, +// ); +// let raw_txn_with_data = +// RawTransactionWithData::new_multi_agent(txn.clone(), vec![*secondary_signer.address()]); +// let sender_sig = MultiEd25519PrivateKey::new(sender_privkeys, threshold) +// .unwrap() +// .sign(&raw_txn_with_data); +// let secondary_signer_sig = MultiEd25519PrivateKey::new(secondary_signer_privkeys, threshold) +// .unwrap() +// .sign(&raw_txn_with_data); +// let signed_txn = SignedTransaction::new_multi_agent( +// txn, +// AccountAuthenticator::multi_ed25519(sender_multi_ed_public_key, sender_sig), +// vec![*secondary_signer.address()], +// vec![AccountAuthenticator::multi_ed25519( +// secondary_signer_multi_ed_public_key, +// secondary_signer_sig, +// )], +// ); +// +// // Transaction will fail validation because the number of signatures exceeds the maximum number +// // of signatures allowed. +// assert_prologue_parity!( +// executor.verify_transaction(signed_txn.clone()).status(), +// executor.execute_transaction(signed_txn).status(), +// StatusCode::INVALID_SIGNATURE +// ); +// } +// +// #[test] +// fn verify_multi_agent_wrong_number_of_signer() { +// let mut executor = FakeExecutor::from_genesis_file(); +// executor.set_golden_file(current_function_name!()); +// let sender = executor.create_raw_account_data(1_000_010, 10); +// let secondary_signer = executor.create_raw_account_data(100_100, 100); +// let third_signer = executor.create_raw_account_data(100_100, 100); +// +// executor.add_account_data(&sender); +// executor.add_account_data(&secondary_signer); +// executor.add_account_data(&third_signer); +// +// // Number of secondary signers according is 2 but we only +// // include the signature of one of the secondary signers. +// let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( +// *sender.address(), +// vec![*secondary_signer.address(), *third_signer.address()], +// 10, +// &sender.account().privkey, +// sender.account().pubkey.clone(), +// vec![&secondary_signer.account().privkey], +// vec![secondary_signer.account().pubkey.clone()], +// Some(multi_agent_mint_script(10, 0)), +// ); +// assert_prologue_parity!( +// executor.verify_transaction(signed_txn.clone()).status(), +// executor.execute_transaction(signed_txn).status(), +// StatusCode::SECONDARY_KEYS_ADDRESSES_COUNT_MISMATCH +// ); +// } +// +// #[test] +// fn verify_multi_agent_duplicate_sender() { +// let mut executor = FakeExecutor::from_genesis_file(); +// executor.set_golden_file(current_function_name!()); +// let sender = executor.create_raw_account_data(1_000_010, 10); +// let secondary_signer = executor.create_raw_account_data(100_100, 100); +// +// executor.add_account_data(&sender); +// executor.add_account_data(&secondary_signer); +// // Duplicates in signers: sender and secondary signer have the same address. +// let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( +// *sender.address(), +// vec![*sender.address()], +// 10, +// &sender.account().privkey, +// sender.account().pubkey.clone(), +// vec![&sender.account().privkey], +// vec![sender.account().pubkey.clone()], +// Some(multi_agent_swap_script(10, 10)), +// ); +// assert_prologue_parity!( +// executor.verify_transaction(signed_txn.clone()).status(), +// executor.execute_transaction(signed_txn).status(), +// StatusCode::SIGNERS_CONTAIN_DUPLICATES +// ); +// } +// +// #[test] +// fn verify_multi_agent_duplicate_secondary_signer() { +// let mut executor = FakeExecutor::from_genesis_file(); +// executor.set_golden_file(current_function_name!()); +// let sender = executor.create_raw_account_data(1_000_010, 10); +// let secondary_signer = executor.create_raw_account_data(100_100, 100); +// let third_signer = executor.create_raw_account_data(100_100, 100); +// +// executor.add_account_data(&sender); +// executor.add_account_data(&secondary_signer); +// executor.add_account_data(&third_signer); +// +// // Duplicates in secondary signers. +// let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( +// *sender.address(), +// vec![ +// *secondary_signer.address(), +// *third_signer.address(), +// *secondary_signer.address(), +// ], +// 10, +// &sender.account().privkey, +// sender.account().pubkey.clone(), +// vec![ +// &secondary_signer.account().privkey, +// &third_signer.account().privkey, +// &secondary_signer.account().privkey, +// ], +// vec![ +// secondary_signer.account().pubkey.clone(), +// third_signer.account().pubkey.clone(), +// secondary_signer.account().pubkey.clone(), +// ], +// None, +// ); +// assert_prologue_parity!( +// executor.verify_transaction(signed_txn.clone()).status(), +// executor.execute_transaction(signed_txn).status(), +// StatusCode::SIGNERS_CONTAIN_DUPLICATES +// ); +// } +// +// #[test] +// fn verify_multi_agent_nonexistent_secondary_signer() { +// let mut executor = FakeExecutor::from_genesis_file(); +// executor.set_golden_file(current_function_name!()); +// let sender = executor.create_raw_account_data(1_000_010, 10); +// let secondary_signer = executor.create_raw_account_data(100_100, 100); +// +// executor.add_account_data(&sender); +// +// // Duplicates in signers: sender and secondary signer have the same address. +// let signed_txn = transaction_test_helpers::get_test_unchecked_multi_agent_txn( +// *sender.address(), +// vec![*secondary_signer.address()], +// 10, +// &sender.account().privkey, +// sender.account().pubkey.clone(), +// vec![&secondary_signer.account().privkey], +// vec![secondary_signer.account().pubkey.clone()], +// Some(multi_agent_swap_script(10, 10)), +// ); +// assert_prologue_parity!( +// executor.verify_transaction(signed_txn.clone()).status(), +// executor.execute_transaction(signed_txn).status(), +// StatusCode::SENDING_ACCOUNT_DOES_NOT_EXIST +// ); +// } #[test] fn verify_reserved_sender() { @@ -382,7 +416,7 @@ fn verify_reserved_sender() { // Generate a new key pair to try and sign things with. let private_key = Ed25519PrivateKey::generate_for_testing(); let program = encode_peer_to_peer_with_metadata_script( - account_config::xus_tag(), + account_config::stc_type_tag(), *sender.address(), 100, vec![], @@ -397,7 +431,7 @@ fn verify_reserved_sender() { ); assert_prologue_parity!( - executor.verify_transaction(signed_txn.clone()).status(), + executor.verify_transaction(signed_txn.clone()).unwrap().status_code(), executor.execute_transaction(signed_txn).status(), StatusCode::SENDING_ACCOUNT_DOES_NOT_EXIST ); @@ -424,42 +458,51 @@ fn verify_simple_payment() { TransactionArgument::U8Vector(vec![]), ]; - let p2p_script = LegacyStdlibScript::PeerToPeerWithMetadata - .compiled_bytes() - .into_vec(); + let p2p_script = encode_peer_to_peer_with_metadata_script( + stc_type_tag(), + receiver.account().address().clone(), + transfer_amount, + vec![], + vec![], + ); // Create a new transaction that has the exact right sequence number. let txn = sender .account() .transaction() - .script(Script::new( - p2p_script.clone(), - vec![account_config::xus_tag()], - args.clone(), - )) + .script(p2p_script.clone()) .sequence_number(10) .sign(); - assert_eq!(executor.verify_transaction(txn).status(), None); + + // let txn = peer_to_peer_txn( + // sender, + // receiver, + // 10, + // transfer_amount, + // ); + assert_eq!(executor.verify_transaction(txn), None); + + let ( + public_key, + private_key + ) = sender.account().ed25519_key_pair(); // Create a new transaction that has the bad auth key. let txn = receiver .account() .transaction() - .script(Script::new( - p2p_script.clone(), - vec![account_config::xus_tag()], - args.clone(), - )) + .script(p2p_script.clone()) .sequence_number(10) .max_gas_amount(100_000) .gas_unit_price(1) .raw() - .sign(&sender.account().privkey, sender.account().pubkey.clone()) + .sign(&private_key, public_key) .unwrap() .into_inner(); + drop(private_key); assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor.verify_transaction(txn.clone()).unwrap().status_code(), executor.execute_transaction(txn).status(), StatusCode::INVALID_AUTH_KEY ); @@ -468,15 +511,19 @@ fn verify_simple_payment() { let txn = sender .account() .transaction() - .script(Script::new( - p2p_script.clone(), - vec![account_config::xus_tag()], - args.clone(), - )) + .script( + p2p_script.clone() + // Script::new( + // p2p_script.clone(), + // vec![account_config::stc_type_tag()], + // args.clone(), + // ) + ) .sequence_number(1) .sign(); + assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor.verify_transaction(txn.clone()).unwrap().status_code(), executor.execute_transaction(txn).status(), StatusCode::SEQUENCE_NUMBER_TOO_OLD ); @@ -485,34 +532,42 @@ fn verify_simple_payment() { let txn = sender .account() .transaction() - .script(Script::new( - p2p_script.clone(), - vec![account_config::xus_tag()], - args.clone(), - )) + .script( + p2p_script.clone() + // Script::new( + // p2p_script.clone(), + // vec![account_config::stc_type_tag()], + // args.clone(), + // ) + ) .sequence_number(11) .sign(); - assert_prologue_disparity!( - executor.verify_transaction(txn.clone()).status() => None, - executor.execute_transaction(txn).status() => - TransactionStatus::Discard(StatusCode::SEQUENCE_NUMBER_TOO_NEW) - ); + + // TODO(bob): e2e-testsuite + // assert_prologue_disparity!( + // executor.verify_transaction(txn.clone()) => None, + // executor.execute_transaction(txn).status() => + // TransactionStatus::Discard(StatusCode::SEQUENCE_NUMBER_TOO_NEW) + // ); // Create a new transaction that doesn't have enough balance to pay for gas. let txn = sender .account() .transaction() - .script(Script::new( - p2p_script.clone(), - vec![account_config::xus_tag()], - args.clone(), - )) + .script( + p2p_script.clone() + // Script::new( + // p2p_script.clone(), + // vec![account_config::stc_type_tag()], + // args.clone(), + // ) + ) .sequence_number(10) .max_gas_amount(1_000_000) .gas_unit_price(1) .sign(); assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor.verify_transaction(txn.clone()).unwrap().status_code(), executor.execute_transaction(txn).status(), StatusCode::INSUFFICIENT_BALANCE_FOR_TRANSACTION_FEE ); @@ -522,15 +577,18 @@ fn verify_simple_payment() { let txn = bogus_account .account() .transaction() - .script(Script::new( - p2p_script.clone(), - vec![account_config::xus_tag()], - args.clone(), - )) + .script( + p2p_script.clone() + // Script::new( + // p2p_script.clone(), + // vec![account_config::stc_type_tag()], + // args.clone(), + // ) + ) .sequence_number(10) .sign(); assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor.verify_transaction(txn.clone()).unwrap().status_code(), executor.execute_transaction(txn).status(), StatusCode::SENDING_ACCOUNT_DOES_NOT_EXIST ); @@ -541,59 +599,65 @@ fn verify_simple_payment() { // We test these in the reverse order that they appear in verify_transaction, and build up // the errors one-by-one to make sure that we are both catching all of them, and // that we are doing so in the specified order. - let gas_constants = &GasConstants::default(); + let gas_constants = &G_TEST_GAS_CONSTANTS; let txn = sender .account() .transaction() - .script(Script::new( - p2p_script.clone(), - vec![account_config::xus_tag()], - args.clone(), - )) + .script( + p2p_script.clone() + // Script::new( + // p2p_script.clone(), + // vec![account_config::stc_type_tag()], + // args.clone(), + // ) + ) .sequence_number(10) - .gas_unit_price(gas_constants.max_price_per_gas_unit.get() + 1) + .gas_unit_price(gas_constants.max_price_per_gas_unit + 1) .max_gas_amount(1_000_000) .sign(); assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor.verify_transaction(txn.clone()).unwrap().status_code(), executor.execute_transaction(txn).status(), StatusCode::GAS_UNIT_PRICE_ABOVE_MAX_BOUND ); // Test for a max_gas_amount that is insufficient to pay the minimum fee. // Find the minimum transaction gas units and subtract 1. - let mut gas_limit = gas_constants - .to_external_units(gas_constants.min_transaction_gas_units) - .get(); + let mut gas_limit = gas_constants.min_transaction_gas_units; if gas_limit > 0 { gas_limit -= 1; } // Calculate how many extra bytes of transaction arguments to add to ensure // that the minimum transaction gas gets rounded up when scaling to the // external gas units. (Ignore the size of the script itself for simplicity.) - let extra_txn_bytes = if gas_constants.gas_unit_scaling_factor - > gas_constants.min_transaction_gas_units.get() + + // TODO(e2e-testsuite) + let _extra_txn_bytes = if gas_constants.gas_unit_scaling_factor + > gas_constants.min_transaction_gas_units { - gas_constants.large_transaction_cutoff.get() - + (gas_constants.gas_unit_scaling_factor / gas_constants.intrinsic_gas_per_byte.get()) + gas_constants.large_transaction_cutoff + + (gas_constants.gas_unit_scaling_factor / gas_constants.intrinsic_gas_per_byte) } else { 0 }; let txn = sender .account() .transaction() - .script(Script::new( - p2p_script.clone(), - vec![account_config::xus_tag()], - vec![TransactionArgument::U8(42); extra_txn_bytes as usize], - )) + .script( + p2p_script.clone() + // Script::new( + // p2p_script.clone(), + // vec![account_config::stc_type_tag()], + // vec![TransactionArgument::U8(42); extra_txn_bytes as usize], + // ) + ) .sequence_number(10) .max_gas_amount(gas_limit) - .gas_unit_price(gas_constants.max_price_per_gas_unit.get()) + .gas_unit_price(gas_constants.max_price_per_gas_unit) .sign(); assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor.verify_transaction(txn.clone()).unwrap().status_code(), executor.execute_transaction(txn).status(), StatusCode::MAX_GAS_UNITS_BELOW_MIN_TRANSACTION_GAS_UNITS ); @@ -601,17 +665,19 @@ fn verify_simple_payment() { let txn = sender .account() .transaction() - .script(Script::new( - p2p_script.clone(), - vec![account_config::xus_tag()], - args, - )) + .script(p2p_script.clone() + // Script::new( + // p2p_script.clone(), + // vec![account_config::stc_type_tag()], + // args, + // ) + ) .sequence_number(10) - .max_gas_amount(gas_constants.maximum_number_of_gas_units.get() + 1) - .gas_unit_price(gas_constants.max_price_per_gas_unit.get()) + .max_gas_amount(gas_constants.maximum_number_of_gas_units + 1) + .gas_unit_price(gas_constants.max_price_per_gas_unit) .sign(); assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor.verify_transaction(txn.clone()).unwrap().status_code(), executor.execute_transaction(txn).status(), StatusCode::MAX_GAS_UNITS_EXCEEDS_MAX_GAS_UNITS_BOUND ); @@ -619,23 +685,26 @@ fn verify_simple_payment() { let txn = sender .account() .transaction() - .script(Script::new( - p2p_script.clone(), - vec![account_config::xus_tag()], - vec![TransactionArgument::U8(42); MAX_TRANSACTION_SIZE_IN_BYTES as usize], - )) + .script( + p2p_script.clone() + // Script::new( + // p2p_script.clone(), + // vec![account_config::stc_type_tag()], + // vec![TransactionArgument::U8(42); MAX_TRANSACTION_SIZE_IN_BYTES as usize], + // ) + ) .sequence_number(10) - .max_gas_amount(gas_constants.maximum_number_of_gas_units.get() + 1) - .gas_unit_price(gas_constants.max_price_per_gas_unit.get()) + .max_gas_amount(gas_constants.maximum_number_of_gas_units + 1) + .gas_unit_price(gas_constants.max_price_per_gas_unit) .sign(); assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor.verify_transaction(txn.clone()).unwrap().status_code(), executor.execute_transaction(txn).status(), StatusCode::EXCEEDED_MAX_TRANSACTION_SIZE ); // Create a new transaction that swaps the two arguments. - let args: Vec = vec![ + let _args: Vec = vec![ TransactionArgument::U64(transfer_amount), TransactionArgument::Address(*receiver.address()), ]; @@ -643,11 +712,14 @@ fn verify_simple_payment() { let txn = sender .account() .transaction() - .script(Script::new( + .script( p2p_script.clone(), - vec![account_config::xus_tag()], - args, - )) + // Script::new( + // p2p_script.clone(), + // vec![account_config::stc_type_tag()], + // args, + // ) + ) .sequence_number(10) .max_gas_amount(100_000) .gas_unit_price(1) @@ -662,11 +734,14 @@ fn verify_simple_payment() { let txn = sender .account() .transaction() - .script(Script::new( - p2p_script, - vec![account_config::xus_tag()], - vec![], - )) + .script( + p2p_script.clone() + // Script::new( + // p2p_script, + // vec![account_config::stc_type_tag()], + // vec![], + // ) + ) .sequence_number(10) .max_gas_amount(100_000) .gas_unit_price(1) @@ -700,7 +775,10 @@ pub fn test_allowlist() { .gas_unit_price(1) .sign(); assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor + .verify_transaction(txn.clone()) + .unwrap() + .status_code(), executor.execute_transaction(txn).status(), StatusCode::UNKNOWN_SCRIPT ); @@ -709,8 +787,9 @@ pub fn test_allowlist() { #[test] pub fn test_arbitrary_script_execution() { // create a FakeExecutor with a genesis from file - let mut executor = - FakeExecutor::from_genesis_with_options(VMPublishingOption::custom_scripts()); + // let mut executor = + // FakeExecutor::from_genesis_with_options(VMPublishingOption::custom_scripts()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // create an empty transaction @@ -728,7 +807,7 @@ pub fn test_arbitrary_script_execution() { .max_gas_amount(100_000) .gas_unit_price(1) .sign(); - assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!(executor.verify_transaction(txn.clone()), None); let status = executor.execute_transaction(txn).status().clone(); assert!(!status.is_discarded()); assert_eq!( @@ -741,8 +820,9 @@ pub fn test_arbitrary_script_execution() { #[test] pub fn test_publish_from_diem_root() { // create a FakeExecutor with a genesis from file - let mut executor = - FakeExecutor::from_genesis_with_options(VMPublishingOption::custom_scripts()); + // let mut executor = + // FakeExecutor::from_genesis_with_options(VMPublishingOption::custom_scripts()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // create a transaction trying to publish a new module. @@ -782,7 +862,10 @@ pub fn test_publish_from_diem_root() { .gas_unit_price(1) .sign(); assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor + .verify_transaction(txn.clone()) + .unwrap() + .status_code(), executor.execute_transaction(txn).status(), StatusCode::INVALID_MODULE_PUBLISHER ); @@ -794,20 +877,22 @@ fn verify_expiration_time() { let mut executor = test_env.executor; let sender = executor.create_raw_account_data(900_000, 0); executor.add_account_data(&sender); - let private_key = &sender.account().privkey; + + let (public_key, private_key) = sender.account().ed25519_key_pair(); + let txn = transaction_test_helpers::get_test_signed_transaction( *sender.address(), 0, /* sequence_number */ - private_key, - private_key.public_key(), + &private_key, + public_key.clone(), None, /* script */ 0, /* expiration_time */ 0, /* gas_unit_price */ - account_config::XUS_NAME.to_owned(), + STC_TOKEN_CODE_STR.to_string(), None, /* max_gas_amount */ ); assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor.verify_transaction(txn.clone()).unwrap().status_code(), executor.execute_transaction(txn).status(), StatusCode::TRANSACTION_EXPIRED ); @@ -817,16 +902,16 @@ fn verify_expiration_time() { let txn = transaction_test_helpers::get_test_signed_transaction( *sender.address(), 10, /* sequence_number */ - private_key, - private_key.public_key(), + &private_key, + public_key.clone(), None, /* script */ 0, /* expiration_time */ 0, /* gas_unit_price */ - account_config::XUS_NAME.to_owned(), + STC_TOKEN_CODE_STR.to_string(), None, /* max_gas_amount */ ); assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor.verify_transaction(txn.clone()).unwrap().status_code(), executor.execute_transaction(txn).status(), StatusCode::TRANSACTION_EXPIRED ); @@ -840,17 +925,20 @@ fn verify_chain_id() { let mut executor = test_env.executor; let sender = executor.create_raw_account_data(900_000, 0); executor.add_account_data(&sender); + + let (public_key, private_key) = sender.account().ed25519_key_pair(); + let private_key = Ed25519PrivateKey::generate_for_testing(); let txn = transaction_test_helpers::get_test_txn_with_chain_id( *sender.address(), 0, &private_key, - private_key.public_key(), + public_key, // all tests use ChainId::test() for chain_id,so pick something different ChainId::new(ChainId::test().id() + 1), ); assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor.verify_transaction(txn.clone()).unwrap().status_code(), executor.execute_transaction(txn).status(), StatusCode::BAD_CHAIN_ID ); @@ -864,12 +952,14 @@ fn verify_gas_currency_with_bad_identifier() { let mut executor = test_env.executor; let sender = executor.create_raw_account_data(900_000, 0); executor.add_account_data(&sender); - let private_key = &sender.account().privkey; + //let private_key = &sender.account().privkey; + + let (public_key, private_key) = sender.account().ed25519_key_pair(); let txn = transaction_test_helpers::get_test_signed_transaction( *sender.address(), 0, /* sequence_number */ - private_key, - private_key.public_key(), + &private_key, + public_key, None, /* script */ u64::MAX, /* expiration_time */ 0, /* gas_unit_price */ @@ -879,7 +969,7 @@ fn verify_gas_currency_with_bad_identifier() { None, /* max_gas_amount */ ); assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor.verify_transaction(txn.clone()).unwrap().status_code(), executor.execute_transaction(txn).status(), StatusCode::INVALID_GAS_SPECIFIER ); @@ -893,12 +983,12 @@ fn verify_gas_currency_code() { let mut executor = test_env.executor; let sender = executor.create_raw_account_data(900_000, 0); executor.add_account_data(&sender); - let private_key = &sender.account().privkey; + let (public_key, private_key) = sender.account().ed25519_key_pair(); let txn = transaction_test_helpers::get_test_signed_transaction( *sender.address(), 0, /* sequence_number */ - private_key, - private_key.public_key(), + &private_key, + public_key, None, /* script */ u64::MAX, /* expiration_time */ 0, /* gas_unit_price */ @@ -906,7 +996,7 @@ fn verify_gas_currency_code() { None, /* max_gas_amount */ ); assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor.verify_transaction(txn.clone()).unwrap().status_code(), executor.execute_transaction(txn).status(), StatusCode::CURRENCY_INFO_DOES_NOT_EXIST ); @@ -920,12 +1010,12 @@ fn verify_max_sequence_number() { let mut executor = test_env.executor; let sender = executor.create_raw_account_data(900_000, std::u64::MAX); executor.add_account_data(&sender); - let private_key = &sender.account().privkey; + let (public_key, private_key) = sender.account().ed25519_key_pair(); let txn = transaction_test_helpers::get_test_signed_transaction( *sender.address(), std::u64::MAX, /* sequence_number */ - private_key, - private_key.public_key(), + &private_key, + public_key, None, /* script */ u64::MAX, /* expiration_time */ 0, /* gas_unit_price */ @@ -933,7 +1023,7 @@ fn verify_max_sequence_number() { None, /* max_gas_amount */ ); assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor.verify_transaction(txn.clone()).unwrap().status_code(), executor.execute_transaction(txn).status(), StatusCode::SEQUENCE_NUMBER_TOO_BIG ); @@ -944,8 +1034,9 @@ fn verify_max_sequence_number() { #[test] pub fn test_no_publishing_diem_root_sender() { // create a FakeExecutor with a genesis from file - let mut executor = - FakeExecutor::from_genesis_with_options(VMPublishingOption::custom_scripts()); + // let mut executor = + // FakeExecutor::from_genesis_with_options(VMPublishingOption::custom_scripts()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // create a transaction trying to publish a new module. @@ -980,7 +1071,7 @@ pub fn test_no_publishing_diem_root_sender() { .sequence_number(0) .max_gas_amount(100_000) .sign(); - assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!(executor.verify_transaction(txn.clone()), None); assert_eq!( executor.execute_transaction(txn).status(), &TransactionStatus::Keep(KeptVMStatus::Executed) @@ -990,7 +1081,7 @@ pub fn test_no_publishing_diem_root_sender() { #[test] pub fn test_open_publishing_invalid_address() { // create a FakeExecutor with a genesis from file - let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // create a transaction trying to publish a new module. @@ -1052,7 +1143,7 @@ pub fn test_open_publishing_invalid_address() { #[test] pub fn test_open_publishing() { // create a FakeExecutor with a genesis from file - let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // create a transaction trying to publish a new module. @@ -1091,7 +1182,7 @@ pub fn test_open_publishing() { .max_gas_amount(100_000) .gas_unit_price(1) .sign(); - assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!(executor.verify_transaction(txn.clone()), None); assert_eq!( executor.execute_transaction(txn).status(), &TransactionStatus::Keep(KeptVMStatus::Executed) @@ -1147,9 +1238,8 @@ fn good_module_uses_bad( ); let compiler = Compiler { - deps: diem_framework_releases::current_modules() + deps: stdlib_compiled_modules(StdLibOptions::Compiled(Latest)) .iter() - .chain(std::iter::once(&bad_dep)) .collect(), }; let module = compiler @@ -1162,7 +1252,7 @@ fn good_module_uses_bad( #[test] fn test_script_dependency_fails_verification() { - let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // Get a module that fails verification into the store. @@ -1198,7 +1288,7 @@ fn test_script_dependency_fails_verification() { .sign(); // As of now, we verify module/script dependencies. This will result in an // invariant violation as we try to load `Test` - assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!(executor.verify_transaction(txn.clone()), None); match executor.execute_transaction(txn).status() { TransactionStatus::Discard(status) => { assert_eq!(status, &StatusCode::UNEXPECTED_VERIFIER_ERROR); @@ -1209,7 +1299,7 @@ fn test_script_dependency_fails_verification() { #[test] fn test_module_dependency_fails_verification() { - let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // Get a module that fails verification into the store. @@ -1221,7 +1311,7 @@ fn test_module_dependency_fails_verification() { executor.add_account_data(&sender); let good_module = { let (_, serialized_module) = good_module_uses_bad(*sender.address(), bad_module); - diem_types::transaction::Module::new(serialized_module) + transaction::Module::new(serialized_module) }; let txn = sender @@ -1234,7 +1324,7 @@ fn test_module_dependency_fails_verification() { .sign(); // As of now, we verify module/script dependencies. This will result in an // invariant violation as we try to load `Test` - assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!(executor.verify_transaction(txn.clone()), None); match executor.execute_transaction(txn).status() { TransactionStatus::Discard(status) => { assert_eq!(status, &StatusCode::UNEXPECTED_VERIFIER_ERROR); @@ -1245,7 +1335,7 @@ fn test_module_dependency_fails_verification() { #[test] fn test_type_tag_dependency_fails_verification() { - let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // Get a module that fails verification into the store. @@ -1272,12 +1362,12 @@ fn test_type_tag_dependency_fails_verification() { .transaction() .script(Script::new( script, - vec![TypeTag::Struct(StructTag { + vec![TypeTag::Struct(Box::new(StructTag { address: account_config::CORE_CODE_ADDRESS, module: Identifier::new("Test").unwrap(), name: Identifier::new("S1").unwrap(), type_params: vec![], - })], + }))], vec![], )) .sequence_number(10) @@ -1286,7 +1376,7 @@ fn test_type_tag_dependency_fails_verification() { .sign(); // As of now, we verify module/script dependencies. This will result in an // invariant violation as we try to load `Test` - assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!(executor.verify_transaction(txn.clone()), None); match executor.execute_transaction(txn).status() { TransactionStatus::Discard(status) => { assert_eq!(status, &StatusCode::UNEXPECTED_VERIFIER_ERROR); @@ -1297,7 +1387,7 @@ fn test_type_tag_dependency_fails_verification() { #[test] fn test_script_transitive_dependency_fails_verification() { - let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // Get a module that fails verification into the store. @@ -1337,7 +1427,7 @@ fn test_script_transitive_dependency_fails_verification() { .sign(); // As of now, we verify module/script dependencies. This will result in an // invariant violation as we try to load `Test` - assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!(executor.verify_transaction(txn.clone()), None); match executor.execute_transaction(txn).status() { TransactionStatus::Discard(status) => { assert_eq!(status, &StatusCode::UNEXPECTED_VERIFIER_ERROR); @@ -1348,7 +1438,7 @@ fn test_script_transitive_dependency_fails_verification() { #[test] fn test_module_transitive_dependency_fails_verification() { - let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // Get a module that fails verification into the store. @@ -1381,7 +1471,7 @@ fn test_module_transitive_dependency_fails_verification() { let compiler = Compiler { deps: vec![&good_module], }; - diem_types::transaction::Module::new( + transaction::Module::new( compiler .into_module_blob(module_code.as_str()) .expect("Module compilation failed"), @@ -1398,7 +1488,7 @@ fn test_module_transitive_dependency_fails_verification() { .sign(); // As of now, we verify module/script dependencies. This will result in an // invariant violation as we try to load `Test` - assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!(executor.verify_transaction(txn.clone()), None); match executor.execute_transaction(txn).status() { TransactionStatus::Discard(status) => { assert_eq!(status, &StatusCode::UNEXPECTED_VERIFIER_ERROR); @@ -1409,7 +1499,7 @@ fn test_module_transitive_dependency_fails_verification() { #[test] fn test_type_tag_transitive_dependency_fails_verification() { - let mut executor = FakeExecutor::from_genesis_with_options(VMPublishingOption::open()); + let mut executor = FakeExecutor::from_test_genesis(); executor.set_golden_file(current_function_name!()); // Get a module that fails verification into the store. @@ -1441,12 +1531,12 @@ fn test_type_tag_transitive_dependency_fails_verification() { .transaction() .script(Script::new( script, - vec![TypeTag::Struct(StructTag { + vec![TypeTag::Struct(Box::new(StructTag { address: account_config::CORE_CODE_ADDRESS, module: Identifier::new("Test2").unwrap(), name: Identifier::new("S").unwrap(), type_params: vec![], - })], + }))], vec![], )) .sequence_number(10) @@ -1455,7 +1545,7 @@ fn test_type_tag_transitive_dependency_fails_verification() { .sign(); // As of now, we verify module/script dependencies. This will result in an // invariant violation as we try to load `Test` - assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!(executor.verify_transaction(txn.clone()), None); match executor.execute_transaction(txn).status() { TransactionStatus::Discard(status) => { assert_eq!(status, &StatusCode::UNEXPECTED_VERIFIER_ERROR); @@ -1472,17 +1562,27 @@ fn charge_gas_invalid_args() { executor.add_account_data(&sender); // get a SignedTransaction + let script = encode_peer_to_peer_with_metadata_script( + stc_type_tag(), + AccountAddress::random(), + 1, + vec![], + vec![] + ); let txn = sender .account() .transaction() - .script(Script::new( - LegacyStdlibScript::PeerToPeerWithMetadata - .compiled_bytes() - .into_vec(), - vec![account_config::xus_tag()], - // Don't pass any arguments - vec![], - )) + .script( + script + // Script::new( + // LegacyStdlibScript::PeerToPeerWithMetadata + // .compiled_bytes() + // .into_vec(), + // vec![account_config::stc_type_tag()], + // // Don't pass any arguments + // vec![], + // ) + ) .sequence_number(0) .max_gas_amount(gas_costs::TXN_RESERVED) .sign(); @@ -1534,20 +1634,20 @@ pub fn publish_and_register_new_currency() { .module(module) .sequence_number(0) .sign(); - assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!(executor.verify_transaction(txn.clone()), None); assert_eq!( executor.execute_and_apply(txn).status(), &TransactionStatus::Keep(KeptVMStatus::Executed) ); - let coin_tag = account_config::type_tag_for_currency_code(Identifier::new("COIN").unwrap()); + let coin_tag = stc_type_tag(); //account_config::type_tag_for_currency_code(Identifier::new("COIN").unwrap()); { let program = { let code = r#" - import 0x1.COIN; + import 0x1.STC; main(lr_account: signer, tc_account: signer) { label b0: - COIN.initialize(&lr_account, &tc_account); + STC.initialize(&lr_account, &tc_account); return; } "#; @@ -1558,10 +1658,7 @@ pub fn publish_and_register_new_currency() { }; let txn = sender .transaction() - .write_set(WriteSetPayload::Script { - script: Script::new(program, vec![], vec![]), - execute_as: *tc_account.address(), - }) + .script(Script::new(program, vec![], vec![])) .sequence_number(1) .sign(); executor.new_block(); @@ -1572,7 +1669,7 @@ pub fn publish_and_register_new_currency() { let txn = tc_account .transaction() - .script(transaction_builder::encode_create_designated_dealer_script( + .script(fake_stdlib::encode_create_designated_dealer_script( coin_tag.clone(), 0, *dd.address(), @@ -1597,7 +1694,7 @@ pub fn publish_and_register_new_currency() { let txn = tc_account .transaction() - .script(transaction_builder::encode_tiered_mint_script( + .script(fake_stdlib::encode_tiered_mint_script( coin_tag.clone(), 0, *dd.address(), @@ -1611,26 +1708,26 @@ pub fn publish_and_register_new_currency() { let txn = dd .transaction() - .script( - transaction_builder::encode_peer_to_peer_with_metadata_script( - coin_tag.clone(), - *dd.address(), - 1, - b"".to_vec(), - b"".to_vec(), - ), - ) + .script(encode_peer_to_peer_with_metadata_script( + coin_tag.clone(), + *dd.address(), + 1, + b"".to_vec(), + b"".to_vec(), + )) .gas_unit_price(1) .max_gas_amount(800) - .gas_currency_code("COIN") .sequence_number(0) .sign(); - let balance = executor.read_balance_resource(&dd, Identifier::new("COIN").unwrap()); - assert!(balance.unwrap().coin() > 800); + let balance = executor.read_balance_resource(&dd); + assert!(balance.unwrap().token() > 800); assert_prologue_parity!( - executor.verify_transaction(txn.clone()).status(), + executor + .verify_transaction(txn.clone()) + .unwrap() + .status_code(), executor.execute_transaction(txn.clone()).status(), StatusCode::BAD_TRANSACTION_FEE_CURRENCY ); @@ -1642,7 +1739,7 @@ pub fn publish_and_register_new_currency() { serialize_values(&vec![MoveValue::Signer(*tc_account.address())]), ); - assert_eq!(executor.verify_transaction(txn.clone()).status(), None); + assert_eq!(executor.verify_transaction(txn.clone()), None); assert_eq!( executor.execute_transaction(txn).status(), &TransactionStatus::Keep(KeptVMStatus::Executed) diff --git a/vm/e2e-testsuite/src/tests/write_set.rs b/vm/e2e-testsuite/src/tests/write_set.rs index eb5f373f39..0c3efafba3 100644 --- a/vm/e2e-testsuite/src/tests/write_set.rs +++ b/vm/e2e-testsuite/src/tests/write_set.rs @@ -1,54 +1,75 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_types::{ - access_path::AccessPath, - account_config::{xus_tag, CORE_CODE_ADDRESS}, - chain_id::{ChainId, NamedChain}, - contract_event::ContractEvent, - on_chain_config::new_epoch_event_key, - transaction::{ - authenticator::AuthenticationKey, ChangeSet, TransactionStatus, WriteSetPayload, - }, - vm_status::{KeptVMStatus, StatusCode}, - write_set::{WriteOp, WriteSet, WriteSetMut}, -}; -use move_core_types::{ - identifier::Identifier, - language_storage::{ResourceKey, StructTag}, -}; -use starcoin_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, Uniform}; +use move_core_types::identifier::Identifier; +use move_core_types::language_storage::{StructTag, CORE_CODE_ADDRESS}; +use move_core_types::vm_status::{KeptVMStatus, StatusCode}; +use starcoin_config::ChainNetwork; +use starcoin_crypto::ed25519::Ed25519PrivateKey; +use starcoin_crypto::{PrivateKey, Uniform}; +use starcoin_language_e2e_tests::common_transactions::rotate_key_txn; use starcoin_language_e2e_tests::{ - account, assert_prologue_parity, common_transactions::rotate_key_txn, - test_with_different_versions, transaction_status_eq, versioning::CURRENT_RELEASE_VERSIONS, + account::Account as E2eTestAccount, assert_prologue_parity, test_with_different_versions, + transaction_status_eq, versioning::CURRENT_RELEASE_VERSIONS, +}; +use starcoin_types::account::Account as StarcoinAccount; +use starcoin_vm_types::{ + access_path::AccessPath, + state_store::state_key::StateKey, + state_view::StateView, + transaction::authenticator::AuthenticationKey, + transaction::{Script, SignedUserTransaction, TransactionStatus}, }; +// use starcoin_vm_types::account_config::stc_type_tag; +// use starcoin_vm_types::contract_event::ContractEvent; +// use starcoin_vm_types::on_chain_config::new_epoch_event_key; +use bcs_ext::Sample; +use test_helper::txn::create_account_txn_sent_as_association; + +fn create_account_data_transaction( + account: Option, + init_amount: u128, + seq_num: u64, +) -> SignedUserTransaction { + let stc_acc = match account { + Some(test_acc) => StarcoinAccount::new_genesis_account(test_acc.address().clone()), + None => StarcoinAccount::new(), + }; + create_account_txn_sent_as_association( + &stc_acc, + seq_num, + init_amount, + 0, + &ChainNetwork::new_test(), + ) +} #[test] fn invalid_write_set_signer() { test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { let mut executor = test_env.executor; - let genesis_account = test_env.dr_account; + //let genesis_account = test_env.dr_account; executor.new_block(); + // TODO(BobOng): e2e-testsuit, disable the WriteSetPayload // Create a WriteSet that adds an account on a new address. - let new_account_data = executor.create_raw_account_data(0, 10); - let write_set = new_account_data.to_writeset(); - + //let new_account_data = executor.create_raw_account_data(0, 10); + //let write_set = new_account_data.to_writeset(); // Signing the txn with a key that does not match the sender should fail. - let writeset_txn = genesis_account - .transaction() - .write_set(WriteSetPayload::Direct(ChangeSet::new(write_set, vec![]))) - .sequence_number(test_env.dr_sequence_number) - .raw() - .sign( - &new_account_data.account().privkey, - new_account_data.account().pubkey.clone(), - ) - .unwrap() - .into_inner(); - + // let writeset_txn = genesis_account + // .transaction() + // .payload(WriteSetPayload::Direct(ChangeSet::new(write_set, vec![]))) + // .sequence_number(test_env.dr_sequence_number) + // .raw() + // .sign( + // &new_account_data.account().privkey, + // new_account_data.account().pubkey.clone(), + // ) + // .unwrap() + // .into_inner(); + let writeset_txn = create_account_data_transaction(Option::None, 0, 10); assert_prologue_parity!( - executor.verify_transaction(writeset_txn.clone()).status(), + executor.verify_transaction(writeset_txn.clone()).unwrap().status_code(), executor.execute_transaction(writeset_txn).status(), StatusCode::INVALID_AUTH_KEY ); @@ -60,22 +81,24 @@ fn invalid_write_set_signer() { fn verify_and_execute_writeset() { test_with_different_versions! {CURRENT_RELEASE_VERSIONS, |test_env| { let mut executor = test_env.executor; - let genesis_account = test_env.dr_account; executor.new_block(); + let genesis_account = test_env.dr_account; + // TODO(BobOng): e2e-testsuit, disable the WriteSetPayload // Create a WriteSet that adds an account on a new address. - let new_account_data = executor.create_raw_account_data(0, 10); - let write_set = new_account_data.to_writeset(); - - // (1) Test that a correct WriteSet is executed as expected. - let writeset_txn = genesis_account - .transaction() - .write_set(WriteSetPayload::Direct(ChangeSet::new( - write_set.clone(), - vec![], - ))) - .sequence_number(test_env.dr_sequence_number) - .sign(); + let new_account_data = executor.create_raw_account_data(0, 10); + // let write_set = new_account_data.to_writeset(); + // + // // (1) Test that a correct WriteSet is executed as expected. + // let writeset_txn = genesis_account + // .transaction() + // .write_set(WriteSetPayload::Direct(ChangeSet::new( + // write_set.clone(), + // vec![], + // ))) + // .sequence_number(test_env.dr_sequence_number) + // .sign(); + let writeset_txn = create_account_data_transaction(Option::Some(new_account_data.account().clone()), 0, 10); let output = executor.execute_transaction(writeset_txn.clone()); assert_eq!( output.status(), @@ -83,7 +106,6 @@ fn verify_and_execute_writeset() { ); assert!(executor .verify_transaction(writeset_txn.clone()) - .status() .is_none()); executor.apply_write_set(output.write_set()); @@ -95,33 +117,34 @@ fn verify_and_execute_writeset() { .read_account_resource(new_account_data.account()) .expect("sender must exist"); let updated_sender_balance = executor - .read_balance_resource(new_account_data.account(), account::xus_currency_code()) + .read_balance_resource(new_account_data.account()) .expect("sender balance must exist"); assert_eq!(test_env.dr_sequence_number.checked_add(1).unwrap(), updated_diem_root_account.sequence_number()); - assert_eq!(0, updated_sender_balance.coin()); + assert_eq!(0, updated_sender_balance.token() as u64); assert_eq!(10, updated_sender.sequence_number()); // (2) Cannot reapply the same writeset. assert_prologue_parity!( - executor.verify_transaction(writeset_txn.clone()).status(), + executor.verify_transaction(writeset_txn.clone()).unwrap().status_code(), executor.execute_transaction(writeset_txn).status(), StatusCode::SEQUENCE_NUMBER_TOO_OLD ); // (3) Cannot apply the writeset with future sequence number. - let writeset_txn = genesis_account - .transaction() - .write_set(WriteSetPayload::Direct(ChangeSet::new(write_set, vec![]))) - .sequence_number(test_env.dr_sequence_number.checked_add(10).unwrap()) - .sign(); + // let writeset_txn = genesis_account + // .transaction() + // .write_set(WriteSetPayload::Direct(ChangeSet::new(write_set, vec![]))) + // .sequence_number(test_env.dr_sequence_number.checked_add(10).unwrap()) + // .sign(); + let writeset_txn = create_account_data_transaction(Option::Some(genesis_account), 0, 20); let output = executor.execute_transaction(writeset_txn.clone()); assert_eq!( output.status(), &TransactionStatus::Discard(StatusCode::SEQUENCE_NUMBER_TOO_NEW) ); // "Too new" sequence numbers are accepted during validation. - assert!(executor.verify_transaction(writeset_txn).status().is_none()); + assert!(executor.verify_transaction(writeset_txn).is_none()); } } } @@ -133,155 +156,188 @@ fn bad_writesets() { let genesis_account = test_env.dr_account; executor.new_block(); - // Create a WriteSet that adds an account on a new address - let new_account_data = executor.create_raw_account_data(1000, 10); - let write_set = new_account_data.to_writeset(); - - // (1) A WriteSet signed by an arbitrary account, not Diem root, should be rejected. - let writeset_txn = new_account_data - .account() - .transaction() - .write_set(WriteSetPayload::Direct(ChangeSet::new( - write_set.clone(), - vec![], - ))) - .sequence_number(0) - .sign(); + + // // Create a WriteSet that adds an account on a new address + // let new_account_data = executor.create_raw_account_data(1000, 10); + // let write_set = new_account_data.to_writeset(); + // + // // (1) A WriteSet signed by an arbitrary account, not Diem root, should be rejected. + // let writeset_txn = new_account_data + // .account() + // .transaction() + // .write_set(WriteSetPayload::Direct(ChangeSet::new( + // write_set.clone(), + // vec![], + // ))) + // .sequence_number(0) + // .sign(); + + // TODO(BobOng): e2e-testsuit, disabled the WriteSetPayload + let writeset_txn = create_account_data_transaction(Some(genesis_account), 1000, 10); assert_prologue_parity!( - executor.verify_transaction(writeset_txn.clone()).status(), + executor.verify_transaction(writeset_txn.clone()).unwrap().status_code(), executor.execute_transaction(writeset_txn).status(), StatusCode::REJECTED_WRITE_SET ); + // TODO(BobOng): e2e-testsuit, disabled a invalid Contract Event // (2) A WriteSet containing a reconfiguration event should be dropped. - let event = ContractEvent::new(new_epoch_event_key(), 0, xus_tag(), vec![]); - let writeset_txn = genesis_account - .transaction() - .write_set(WriteSetPayload::Direct(ChangeSet::new( - write_set, - vec![event], - ))) - .sequence_number(test_env.dr_sequence_number) - .sign(); - assert_eq!( - executor.execute_transaction(writeset_txn).status(), - &TransactionStatus::Discard(StatusCode::INVALID_WRITE_SET) - ); - + // let event = ContractEvent::new( + // new_epoch_event_key(), + // 0, + // stc_type_tag(), + // vec![] + // ); + //writeset_txn = create_contract_event_txn(); + // let writeset_txn = genesis_account + // .transaction() + // .write_set(WriteSetPayload::Direct(ChangeSet::new( + // write_set, + // vec![event], + // ))) + // .sequence_number(test_env.dr_sequence_number) + // .sign(); + // assert_eq!( + // executor.execute_transaction(writeset_txn).status(), + // &TransactionStatus::Discard(StatusCode::INVALID_WRITE_SET) + // ); + + // TODO(BobOng): e2e-testsuit, test with unreadable resource // (3) A WriteSet attempting to change DiemWriteSetManager should be dropped. - let key = ResourceKey::new( - *genesis_account.address(), - StructTag { - address: CORE_CODE_ADDRESS, - module: Identifier::new("DiemAccount").unwrap(), - name: Identifier::new("DiemWriteSetManager").unwrap(), - type_params: vec![], - }, - ); - let path = AccessPath::resource_access_path(key); - - let write_set = WriteSetMut::new(vec![(path, WriteOp::Value(vec![]))]) - .freeze() - .unwrap(); - let writeset_txn = genesis_account - .transaction() - .write_set(WriteSetPayload::Direct(ChangeSet::new(write_set, vec![]))) - .sequence_number(test_env.dr_sequence_number) - .sign(); - let output = executor.execute_transaction(writeset_txn); - assert_eq!( - output.status(), - &TransactionStatus::Discard(StatusCode::INVALID_WRITE_SET) - ); - + // let key = ResourceKey::new( + // *genesis_account.address(), + // StructTag { + // address: CORE_CODE_ADDRESS, + // module: Identifier::new("Account").unwrap(), + // name: Identifier::new("Account123").unwrap(), + // type_params: vec![], + // }, + // ); + // let write_set = WriteSetMut::new(vec![(path, WriteOp::Value(vec![]))]) + // .freeze() + // .unwrap(); + // let writeset_txn = genesis_account + // .transaction() + // .write_set(WriteSetPayload::Direct(ChangeSet::new(write_set, vec![]))) + // .sequence_number(test_env.dr_sequence_number) + // .sign(); + // let output = executor.execute_transaction(writeset_txn); + // assert_eq!( + // output.status(), + // &TransactionStatus::Discard(StatusCode::INVALID_WRITE_SET) + // ); + let path = AccessPath::resource_access_path(genesis_account.address().clone(), StructTag { + address: CORE_CODE_ADDRESS, + module: Identifier::new("Account").unwrap(), + name: Identifier::new("Account1234").unwrap(), + type_params: vec![], + }); + assert!(executor.get_state_view().get_state_value(&StateKey::AccessPath(path)).unwrap().is_none()); + + // TODO(BobOng): e2e-testsuit, 4 same as 3 // (4) A WriteSet attempting to change Diem root AccountResource should be dropped. - let key = ResourceKey::new( - *genesis_account.address(), - StructTag { - address: CORE_CODE_ADDRESS, - module: Identifier::new("DiemAccount").unwrap(), - name: Identifier::new("DiemAccount").unwrap(), - type_params: vec![], - }, - ); - let path = AccessPath::resource_access_path(key); - - let write_set = WriteSetMut::new(vec![(path, WriteOp::Value(vec![]))]) - .freeze() - .unwrap(); - let writeset_txn = genesis_account - .transaction() - .write_set(WriteSetPayload::Direct(ChangeSet::new(write_set, vec![]))) - .sequence_number(test_env.dr_sequence_number) - .sign(); - let output = executor.execute_transaction(writeset_txn); - assert_eq!( - output.status(), - &TransactionStatus::Discard(StatusCode::INVALID_WRITE_SET) - ); + // let key = ResourceKey::new( + // *genesis_account.address(), + // StructTag { + // address: CORE_CODE_ADDRESS, + // module: Identifier::new("DiemAccount").unwrap(), + // name: Identifier::new("DiemAccount").unwrap(), + // type_params: vec![], + // }, + // ); + // let path = AccessPath::resource_access_path(key); + // + // let write_set = WriteSetMut::new(vec![(path, WriteOp::Value(vec![]))]) + // .freeze() + // .unwrap(); + // let writeset_txn = genesis_account + // .transaction() + // .write_set(WriteSetPayload::Direct(ChangeSet::new(write_set, vec![]))) + // .sequence_number(test_env.dr_sequence_number) + // .sign(); + // let output = executor.execute_transaction(writeset_txn); + // assert_eq!( + // output.status(), + // &TransactionStatus::Discard(StatusCode::INVALID_WRITE_SET) + // ); // (5) A WriteSet with a bad ChainId should be rejected. - let writeset_txn = genesis_account - .transaction() - .write_set(WriteSetPayload::Direct(ChangeSet::new( - WriteSet::default(), - vec![], - ))) - .sequence_number(test_env.dr_sequence_number) - .chain_id(ChainId::new(NamedChain::DEVNET.id())) - .sign(); - assert_prologue_parity!( - executor.verify_transaction(writeset_txn.clone()).status(), - executor.execute_transaction(writeset_txn).status(), - StatusCode::BAD_CHAIN_ID - ); + // let writeset_txn = genesis_account + // .transaction() + // .write_set(WriteSetPayload::Direct(ChangeSet::new( + // WriteSet::default(), + // vec![], + // ))) + // .sequence_number(test_env.dr_sequence_number) + // .chain_id(ChainId::new(NamedChain::DEVNET.id())) + // .sign(); + // assert_prologue_parity!( + // executor.verify_transaction(writeset_txn.clone()).status(), + // executor.execute_transaction(writeset_txn).status(), + // StatusCode::BAD_CHAIN_ID + // ); // (6) A WriteSet that has expired should be rejected. + // let writeset_txn = genesis_account + // .transaction() + // .write_set(WriteSetPayload::Direct(ChangeSet::new( + // WriteSet::default(), + // vec![], + // ))) + // .sequence_number(test_env.dr_sequence_number) + // .ttl(0) + // .sign(); let writeset_txn = genesis_account - .transaction() - .write_set(WriteSetPayload::Direct(ChangeSet::new( - WriteSet::default(), - vec![], - ))) + .transaction().script(Script::sample()) .sequence_number(test_env.dr_sequence_number) .ttl(0) .sign(); assert_prologue_parity!( - executor.verify_transaction(writeset_txn.clone()).status(), + executor.verify_transaction(writeset_txn.clone()).unwrap().status_code(), executor.execute_transaction(writeset_txn).status(), StatusCode::TRANSACTION_EXPIRED ); // (7) The gas currency specified in the transaction must be valid // (even though WriteSet transactions are not charged for gas). + // let writeset_txn = genesis_account + // .transaction() + // .write_set(WriteSetPayload::Direct(ChangeSet::new( + // WriteSet::default(), + // vec![], + // ))) + // .sequence_number(test_env.dr_sequence_number) + // .gas_currency_code("Bad_ID") + // .sign(); let writeset_txn = genesis_account - .transaction() - .write_set(WriteSetPayload::Direct(ChangeSet::new( - WriteSet::default(), - vec![], - ))) + .transaction().script(Script::sample()) .sequence_number(test_env.dr_sequence_number) .gas_currency_code("Bad_ID") .sign(); assert_prologue_parity!( - executor.verify_transaction(writeset_txn.clone()).status(), + executor.verify_transaction(writeset_txn.clone()).unwrap().status_code(), executor.execute_transaction(writeset_txn).status(), StatusCode::INVALID_GAS_SPECIFIER ); // (8) The gas currency code must also correspond to a registered currency // (even though WriteSet transactions are not charged for gas). + // let writeset_txn = genesis_account + // .transaction() + // .write_set(WriteSetPayload::Direct(ChangeSet::new( + // WriteSet::default(), + // vec![], + // ))) + // .sequence_number(test_env.dr_sequence_number) + // .gas_currency_code("INVALID") + // .sign(); let writeset_txn = genesis_account - .transaction() - .write_set(WriteSetPayload::Direct(ChangeSet::new( - WriteSet::default(), - vec![], - ))) + .transaction().script(Script::sample()) .sequence_number(test_env.dr_sequence_number) .gas_currency_code("INVALID") .sign(); assert_prologue_parity!( - executor.verify_transaction(writeset_txn.clone()).status(), + executor.verify_transaction(writeset_txn.clone()).unwrap().status_code(), executor.execute_transaction(writeset_txn).status(), StatusCode::CURRENCY_INFO_DOES_NOT_EXIST ); @@ -305,24 +361,26 @@ fn transfer_and_execute_writeset() { let pubkey = privkey.public_key(); let new_key_hash = AuthenticationKey::ed25519(&pubkey).to_vec(); + let new_account_data = executor.create_raw_account_data(0, 10); executor.execute_and_apply(rotate_key_txn(&blessed_account, new_key_hash, test_env.tc_sequence_number)); // (2) Create a WriteSet that adds an account on a new address - let new_account_data = executor.create_raw_account_data(0, 10); - let write_set = new_account_data.to_writeset(); - - let writeset_txn = genesis_account - .transaction() - .write_set(WriteSetPayload::Direct(ChangeSet::new(write_set, vec![]))) - .sequence_number(test_env.dr_sequence_number) - .sign(); + // let write_set = new_account_data.to_writeset(); + // + // let writeset_txn = genesis_account + // .transaction() + // .write_set(WriteSetPayload::Direct(ChangeSet::new(write_set, vec![]))) + // .sequence_number(test_env.dr_sequence_number) + // .sign(); + let writeset_txn = create_account_data_transaction( + Some(new_account_data.account().clone()), 0, 10); let output = executor.execute_transaction(writeset_txn.clone()); assert_eq!( output.status(), &TransactionStatus::Keep(KeptVMStatus::Executed) ); - assert!(executor.verify_transaction(writeset_txn).status().is_none()); + assert!(executor.verify_transaction(writeset_txn).is_none()); executor.apply_write_set(output.write_set()); @@ -333,11 +391,11 @@ fn transfer_and_execute_writeset() { .read_account_resource(new_account_data.account()) .expect("sender must exist"); let updated_sender_balance = executor - .read_balance_resource(new_account_data.account(), account::xus_currency_code()) + .read_balance_resource(new_account_data.account()) .expect("sender balance must exist"); assert_eq!(test_env.dr_sequence_number.checked_add(1).unwrap(), updated_diem_root_account.sequence_number()); - assert_eq!(0, updated_sender_balance.coin()); + assert_eq!(0, updated_sender_balance.token() as u64); assert_eq!(10, updated_sender.sequence_number()); // (3) Rotate the accounts key diff --git a/vm/e2e-testsuite/src/tests/writeset_builder.rs b/vm/e2e-testsuite/src/tests/writeset_builder.rs index 4e74344eed..924e7a6eb9 100644 --- a/vm/e2e-testsuite/src/tests/writeset_builder.rs +++ b/vm/e2e-testsuite/src/tests/writeset_builder.rs @@ -1,101 +1,85 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use diem_types::{ - access_path::AccessPath, - on_chain_config::DiemVersion, - transaction::{ChangeSet, Script, TransactionStatus, WriteSetPayload}, - vm_status::KeptVMStatus, - write_set::WriteOp, -}; -use diem_vm::DiemVM; -use diem_writeset_generator::build_changeset; -use move_ir_compiler::Compiler; -use starcoin_language_e2e_tests::{ - account::Account, compile::compile_module, current_function_name, executor::FakeExecutor, -}; #[test] fn build_upgrade_writeset() { - let mut executor = FakeExecutor::from_genesis_file(); - executor.set_golden_file(current_function_name!()); - - // create a transaction trying to publish a new module. - let genesis_account = Account::new_starcoin_root(); - - let program = String::from( - " - module 0x1.M { - public magic(): u64 { label b0: return 42; } - } - ", - ); - - let module = compile_module(&program).0; - let module_bytes = { - let mut v = vec![]; - module.serialize(&mut v).unwrap(); - v - }; - let change_set = { - let (version_writes, events) = build_changeset(executor.get_state_view(), |session| { - session.set_starcoin_version(11); - }) - .into_inner(); - let mut writeset = version_writes.into_mut(); - writeset.push(( - AccessPath::code_access_path(module.self_id()), - WriteOp::Value(module_bytes), - )); - ChangeSet::new(writeset.freeze().unwrap(), events) - }; - - let writeset_txn = genesis_account - .transaction() - .write_set(WriteSetPayload::Direct(change_set)) - .sequence_number(0) - .sign(); - - let output = executor.execute_transaction(writeset_txn.clone()); - assert_eq!( - output.status(), - &TransactionStatus::Keep(KeptVMStatus::Executed) - ); - assert!(executor.verify_transaction(writeset_txn).status().is_none()); - - executor.apply_write_set(output.write_set()); - - let new_vm = DiemVM::new(executor.get_state_view()); - assert_eq!( - new_vm.internals().diem_version().unwrap(), - DiemVersion { major: 11 } - ); - - let script_body = { - let code = r#" -import 0x1.M; - -main(lr_account: signer) { -label b0: - assert(M.magic() == 42, 100); - return; -} -"#; - - let compiler = Compiler { - deps: vec![&module], - }; - compiler.into_script_blob(code).expect("Failed to compile") - }; - - let txn = genesis_account - .transaction() - .script(Script::new(script_body, vec![], vec![])) - .sequence_number(1) - .sign(); - - let output = executor.execute_transaction(txn); - assert_eq!( - output.status(), - &TransactionStatus::Keep(KeptVMStatus::Executed) - ); + // let mut executor = FakeExecutor::from_genesis_file(); + // executor.set_golden_file(current_function_name!()); + // + // // create a transaction trying to publish a new module. + // let genesis_account = Account::new_starcoin_root(); + // + // let program = String::from( + // " + // module 0x1.M { + // public magic(): u64 { label b0: return 42; } + // } + // ", + // ); + // + // let module = compile_module(&program).0; + // let module_bytes = { + // let mut v = vec![]; + // module.serialize(&mut v).unwrap(); + // v + // }; + // let change_set = { + // let (version_writes, events) = build_changeset(executor.get_state_view(), |session| { + // session.set_starcoin_version(11); + // }) + // .into_inner(); + // let mut writeset = version_writes.into_mut(); + // writeset.push(( + // AccessPath::code_access_path(module.self_id()), + // WriteOp::Value(module_bytes), + // )); + // ChangeSet::new(writeset.freeze().unwrap(), events) + // }; + // + // let writeset_txn = genesis_account + // .transaction() + // .write_set(WriteSetPayload::Direct(change_set)) + // .sequence_number(0) + // .sign(); + // + // let output = executor.execute_transaction(writeset_txn.clone()); + // assert_eq!( + // output.status(), + // &TransactionStatus::Keep(KeptVMStatus::Executed) + // ); + // assert!(executor.verify_transaction(writeset_txn).status().is_none()); + // + // executor.apply_write_set(output.write_set()); + // + // let new_vm = StarcoinVM::new(None); + // assert_eq!(new_vm.get_version().unwrap().major, 12); + // + // let script_body = { + // let code = r#" + // import 0x1.M; + // + // main(lr_account: signer) { + // label b0: + // assert(M.magic() == 42, 100); + // return; + // } + // "#; + // + // let compiler = Compiler { + // deps: vec![&module], + // }; + // compiler.into_script_blob(code).expect("Failed to compile") + // }; + // + // let txn = genesis_account + // .transaction() + // .script(Script::new(script_body, vec![], vec![])) + // .sequence_number(1) + // .sign(); + // + // let output = executor.execute_transaction(txn); + // assert_eq!( + // output.status(), + // &TransactionStatus::Keep(KeptVMStatus::Executed) + // ); } diff --git a/vm/transaction-builder/src/lib.rs b/vm/transaction-builder/src/lib.rs index dfdb6c4754..408b5e1f0f 100644 --- a/vm/transaction-builder/src/lib.rs +++ b/vm/transaction-builder/src/lib.rs @@ -6,28 +6,33 @@ use starcoin_config::{genesis_config::G_TOTAL_STC_AMOUNT, ChainNetwork}; use starcoin_crypto::hash::PlainCryptoHash; use starcoin_crypto::HashValue; use starcoin_types::account::Account; -use starcoin_vm_types::access::ModuleAccess; -use starcoin_vm_types::account_address::AccountAddress; -use starcoin_vm_types::account_config; -use starcoin_vm_types::account_config::{core_code_address, genesis_address}; -use starcoin_vm_types::file_format::CompiledModule; -use starcoin_vm_types::genesis_config::ChainId; -use starcoin_vm_types::identifier::Identifier; -use starcoin_vm_types::language_storage::ModuleId; -use starcoin_vm_types::language_storage::{StructTag, TypeTag}; -use starcoin_vm_types::on_chain_config::VMConfig; -use starcoin_vm_types::on_chain_resource::nft::NFTUUID; -use starcoin_vm_types::token::stc::{stc_type_tag, G_STC_TOKEN_CODE}; -use starcoin_vm_types::token::token_code::TokenCode; -use starcoin_vm_types::transaction::authenticator::{AccountPrivateKey, AuthenticationKey}; -use starcoin_vm_types::transaction::{ - Module, Package, RawUserTransaction, ScriptFunction, SignedUserTransaction, Transaction, - TransactionPayload, + +use starcoin_vm_types::{ + access::ModuleAccess, + account_address::AccountAddress, + account_config::{self, core_code_address, genesis_address}, + file_format::CompiledModule, + genesis_config::ChainId, + identifier::Identifier, + language_storage::{ModuleId, StructTag, TypeTag}, + on_chain_config::{GasSchedule, VMConfig}, + on_chain_resource::nft::NFTUUID, + token::{ + stc::{stc_type_tag, G_STC_TOKEN_CODE}, + token_code::TokenCode, + }, + transaction::{ + authenticator::{AccountPrivateKey, AuthenticationKey}, + Module, Package, RawUserTransaction, ScriptFunction, SignedUserTransaction, Transaction, + TransactionPayload, + }, + value::MoveValue, }; -use starcoin_vm_types::value::MoveValue; use std::convert::TryInto; -use stdlib::{module_to_package, stdlib_package}; -pub use stdlib::{stdlib_compiled_modules, stdlib_modules, StdLibOptions, StdlibVersion}; +pub use stdlib::{ + module_to_package, stdlib_compiled_modules, stdlib_modules, stdlib_package, StdLibOptions, + StdlibVersion, +}; pub const DEFAULT_EXPIRATION_TIME: u64 = 40_000; pub const DEFAULT_MAX_GAS_AMOUNT: u64 = 40000000; diff --git a/vm/types/src/account_config/constants/addresses.rs b/vm/types/src/account_config/constants/addresses.rs index 2d2a0bee6d..5f54cdecc3 100644 --- a/vm/types/src/account_config/constants/addresses.rs +++ b/vm/types/src/account_config/constants/addresses.rs @@ -17,6 +17,15 @@ pub fn genesis_address() -> AccountAddress { CORE_CODE_ADDRESS } +pub fn reserved_vm_address() -> AccountAddress { + AccountAddress::new([0u8; AccountAddress::LENGTH]) +} + +pub fn treasury_compliance_account_address() -> AccountAddress { + AccountAddress::from_hex_literal("0xB1E55ED") + .expect("Parsing valid hex literal should always succeed") +} + pub const TABLE_ADDRESS_LIST_LEN: usize = 32; pub const TABLE_ADDRESS_LIST: [&str; TABLE_ADDRESS_LIST_LEN] = [ "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37", "0x38", "0x39", "0x3a", "0x3b", "0x3c", diff --git a/vm/types/src/lib.rs b/vm/types/src/lib.rs index ea86f45141..7770dd5940 100644 --- a/vm/types/src/lib.rs +++ b/vm/types/src/lib.rs @@ -241,3 +241,6 @@ pub mod time; pub mod token; #[cfg(test)] mod unit_tests; + +#[cfg(any(test, feature = "fuzzing"))] +pub mod test_helpers; diff --git a/vm/types/src/on_chain_config/genesis_gas_schedule.rs b/vm/types/src/on_chain_config/genesis_gas_schedule.rs index 5e7e7c4a80..347b3e96c8 100644 --- a/vm/types/src/on_chain_config/genesis_gas_schedule.rs +++ b/vm/types/src/on_chain_config/genesis_gas_schedule.rs @@ -122,7 +122,7 @@ pub fn instruction_table_v1() -> Vec { ), (Nop, GasCost::new(1, 1)), ]; - // Note that the DiemVM is expecting the table sorted by instruction order. + // Note that the StarcoinVM is expecting the table sorted by instruction order. instrs.sort_by_key(|cost| instruction_key(&cost.0)); // { @@ -255,7 +255,7 @@ pub fn instruction_table_v2() -> Vec { (VecUnpack(SignatureIndex::new(0), 0), GasCost::new(572, 1)), (VecSwap(SignatureIndex::new(0)), GasCost::new(1436, 1)), ]; - // Note that the DiemVM is expecting the table sorted by instruction order. + // Note that the StarcoinVM is expecting the table sorted by instruction order. instrs.sort_by_key(|cost| instruction_key(&cost.0)); instrs.into_iter().map(|(_, cost)| cost).collect::>() } diff --git a/vm/types/src/test_helpers/empty_script.mv b/vm/types/src/test_helpers/empty_script.mv new file mode 100644 index 0000000000000000000000000000000000000000..130e051a936a1446371d750b2badfbe5b4ced478 GIT binary patch literal 18 XcmZ1|^O~EHfq{XMl>tOCFfsuE9OVJO literal 0 HcmV?d00001 diff --git a/vm/types/src/test_helpers/mod.rs b/vm/types/src/test_helpers/mod.rs new file mode 100644 index 0000000000..f260d4e0b8 --- /dev/null +++ b/vm/types/src/test_helpers/mod.rs @@ -0,0 +1,4 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +pub mod transaction_test_helpers; diff --git a/vm/types/src/test_helpers/transaction_test_helpers.rs b/vm/types/src/test_helpers/transaction_test_helpers.rs new file mode 100644 index 0000000000..3e15c39492 --- /dev/null +++ b/vm/types/src/test_helpers/transaction_test_helpers.rs @@ -0,0 +1,252 @@ +// Copyright (c) The Diem Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use crate::account_config::STC_TOKEN_CODE_STR; +use crate::transaction::RawUserTransaction; +use crate::{ + genesis_config::ChainId, + transaction::{Module, Script, SignedUserTransaction, TransactionPayload}, +}; +use move_core_types::account_address::AccountAddress; +use starcoin_crypto::ed25519::{Ed25519PrivateKey, Ed25519PublicKey}; +use starcoin_crypto::SigningKey; + +const MAX_GAS_AMOUNT: u64 = 1_000_000; +const TEST_GAS_PRICE: u64 = 0; + +static EMPTY_SCRIPT: &[u8] = include_bytes!("empty_script.mv"); + +// Create an expiration time 'seconds' after now +fn expiration_time(seconds: u64) -> u64 { + std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH) + .expect("System time is before the UNIX_EPOCH") + .as_secs() + + seconds +} + +//struct RawTransaction(AccountAddress, u64, Module, u64, u64, _, u64, _); + +// Test helper for transaction creation +pub fn get_test_signed_module_publishing_transaction( + sender: AccountAddress, + sequence_number: u64, + private_key: &Ed25519PrivateKey, + public_key: Ed25519PublicKey, + module: Module, +) -> SignedUserTransaction { + let expiration_time = expiration_time(10); + let raw_txn = RawUserTransaction::new_module( + sender, + sequence_number, + module, + MAX_GAS_AMOUNT, + TEST_GAS_PRICE, + expiration_time, + ChainId::test(), + ); + let signature = private_key.sign(&raw_txn); + SignedUserTransaction::ed25519(raw_txn, public_key, signature) +} + +// Test helper for transaction creation +pub fn get_test_signed_transaction( + sender: AccountAddress, + sequence_number: u64, + private_key: &Ed25519PrivateKey, + public_key: Ed25519PublicKey, + payload: Option, + expiration_timestamp_secs: u64, + gas_unit_price: u64, + gas_currency_code: String, + max_gas_amount: Option, +) -> SignedUserTransaction { + let raw_txn = RawUserTransaction::new( + sender, + sequence_number, + payload.unwrap_or_else(|| { + TransactionPayload::Script(Script::new(EMPTY_SCRIPT.to_vec(), vec![], vec![])) + }), + max_gas_amount.unwrap_or(MAX_GAS_AMOUNT), + gas_unit_price, + expiration_timestamp_secs, + ChainId::test(), + gas_currency_code, + ); + let signature = private_key.sign(&raw_txn); + SignedUserTransaction::ed25519(raw_txn, public_key, signature) +} + +// Test helper for creating transactions for which the signature hasn't been checked. +pub fn get_test_unchecked_transaction( + sender: AccountAddress, + sequence_number: u64, + private_key: &Ed25519PrivateKey, + public_key: Ed25519PublicKey, + script: Option