From 351cd572e7c3baff9adbf31b587fbb95711ec9ab Mon Sep 17 00:00:00 2001 From: Bowen Wang Date: Sat, 6 Apr 2024 10:48:02 -0700 Subject: [PATCH 1/8] compiles --- chain/chain/src/chain.rs | 10 +- chain/chain/src/chain_update.rs | 2 +- chain/chain/src/garbage_collection.rs | 2 +- chain/chain/src/runtime/mod.rs | 2 +- chain/chain/src/runtime/tests.rs | 7 +- chain/chain/src/store.rs | 10 +- chain/chain/src/test_utils.rs | 6 +- chain/chain/src/test_utils/kv_runtime.rs | 44 +-- chain/chain/src/validate.rs | 4 +- chain/chunks/src/client.rs | 6 +- chain/client/src/client.rs | 9 +- chain/client/src/test_utils/test_env.rs | 2 + chain/indexer/src/streamer/utils.rs | 42 +-- .../src/types/transactions.rs | 2 +- chain/jsonrpc/src/lib.rs | 2 +- chain/pool/src/lib.rs | 24 +- chain/rosetta-rpc/src/lib.rs | 15 +- core/primitives/benches/serialization.rs | 6 +- core/primitives/src/receipt.rs | 262 +++++++++++++++--- core/primitives/src/state_record.rs | 2 +- core/primitives/src/test_utils.rs | 52 +++- core/primitives/src/transaction.rs | 140 +++++++++- core/primitives/src/views.rs | 41 +-- core/store/benches/finalize_bench.rs | 10 +- core/store/src/genesis/state_applier.rs | 10 +- core/store/src/lib.rs | 10 +- core/store/src/test_utils.rs | 7 +- core/store/src/trie/resharding.rs | 10 +- .../genesis-csv-to-json/src/csv_parser.rs | 5 +- .../src/tests/client/benchmarks.rs | 1 + .../src/tests/client/cold_storage.rs | 4 +- .../account_id_in_function_call_permission.rs | 12 +- .../client/features/chunk_nodes_cache.rs | 1 + .../src/tests/client/features/flat_storage.rs | 12 +- .../features/increase_storage_compute_cost.rs | 1 + .../features/lower_storage_key_limit.rs | 12 +- .../src/tests/client/features/nearvm.rs | 8 +- ...restore_receipts_after_fix_apply_chunks.rs | 2 +- .../features/storage_proof_size_limit.rs | 4 +- .../tests/client/features/wallet_contract.rs | 4 + .../client/features/zero_balance_account.rs | 2 + .../src/tests/client/process_blocks.rs | 17 +- .../src/tests/client/resharding.rs | 11 +- .../src/tests/nearcore/rpc_nodes.rs | 2 +- .../src/tests/runtime/deployment.rs | 1 + .../src/tests/standard_cases/mod.rs | 8 +- integration-tests/src/tests/test_errors.rs | 2 + integration-tests/src/user/mod.rs | 1 + integration-tests/src/user/runtime_user.rs | 2 +- nearcore/src/metrics.rs | 4 +- .../src/action_costs.rs | 6 +- .../src/transaction_builder.rs | 1 + runtime/runtime/src/actions.rs | 43 +-- runtime/runtime/src/balance_checker.rs | 62 ++--- runtime/runtime/src/config.rs | 23 +- runtime/runtime/src/lib.rs | 148 +++++----- runtime/runtime/src/prefetch.rs | 20 +- runtime/runtime/src/verifier.rs | 61 ++-- .../runtime/tests/runtime_group_tools/mod.rs | 10 +- runtime/runtime/tests/test_async_calls.rs | 13 + test-utils/runtime-tester/src/run_test.rs | 1 + .../src/single_shard_storage_mutator.rs | 8 +- tools/mirror/src/chain_tracker.rs | 60 ++-- tools/mirror/src/genesis.rs | 24 +- tools/mirror/src/lib.rs | 49 ++-- tools/state-viewer/src/apply_chain_range.rs | 2 +- tools/state-viewer/src/apply_chunk.rs | 6 +- tools/state-viewer/src/contract_accounts.rs | 14 +- tools/state-viewer/src/state_dump.rs | 1 + tools/state-viewer/src/tx_dump.rs | 2 +- 70 files changed, 920 insertions(+), 489 deletions(-) diff --git a/chain/chain/src/chain.rs b/chain/chain/src/chain.rs index f457c3c51f4..55350d2cae5 100644 --- a/chain/chain/src/chain.rs +++ b/chain/chain/src/chain.rs @@ -2930,7 +2930,7 @@ impl Chain { self.chain_store() .check_transaction_validity_period( prev_block_header, - &transaction.transaction.block_hash, + transaction.transaction.block_hash(), transaction_validity_period, ) .map_err(|_| Error::from(Error::InvalidTransactions))?; @@ -2948,7 +2948,7 @@ impl Chain { self.chain_store() .check_transaction_validity_period( &prev_block_header, - &tx.transaction.block_hash, + tx.transaction.block_hash(), self.transaction_validity_period, ) .is_ok() @@ -4324,7 +4324,7 @@ impl Chain { ) -> HashMap> { let mut result = HashMap::new(); for receipt in receipts { - let shard_id = account_id_to_shard_id(&receipt.receiver_id, shard_layout); + let shard_id = account_id_to_shard_id(receipt.receiver_id(), shard_layout); let entry = result.entry(shard_id).or_insert_with(Vec::new); entry.push(receipt) } @@ -4345,8 +4345,8 @@ impl Chain { let mut cache = HashMap::new(); for receipt in receipts { let &mut shard_id = cache - .entry(&receipt.receiver_id) - .or_insert_with(|| account_id_to_shard_id(&receipt.receiver_id, shard_layout)); + .entry(receipt.receiver_id()) + .or_insert_with(|| account_id_to_shard_id(receipt.receiver_id(), shard_layout)); // This unwrap should be safe as we pre-populated the map with all // valid shard ids. result.get_mut(&shard_id).unwrap().push(receipt); diff --git a/chain/chain/src/chain_update.rs b/chain/chain/src/chain_update.rs index b96e828c714..82e946fb743 100644 --- a/chain/chain/src/chain_update.rs +++ b/chain/chain/src/chain_update.rs @@ -135,7 +135,7 @@ impl<'a> ChainUpdate<'a> { let outgoing_receipts = outgoing_receipts .iter() .map(|receipt| { - (receipt.receipt_id, account_id_to_shard_id(&receipt.receiver_id, &shard_layout)) + (*receipt.receipt_id(), account_id_to_shard_id(receipt.receiver_id(), &shard_layout)) }) .collect(); Ok(outgoing_receipts) diff --git a/chain/chain/src/garbage_collection.rs b/chain/chain/src/garbage_collection.rs index 39c2de1e523..a044fcd81ce 100644 --- a/chain/chain/src/garbage_collection.rs +++ b/chain/chain/src/garbage_collection.rs @@ -854,7 +854,7 @@ impl<'a> ChainStoreUpdate<'a> { let mut store_update = self.store().store_update(); match self .get_outgoing_receipts(block_hash, shard_id) - .map(|receipts| receipts.iter().map(|receipt| receipt.receipt_id).collect::>()) + .map(|receipts| receipts.iter().map(|receipt| *receipt.receipt_id()).collect::>()) { Ok(receipt_ids) => { for receipt_id in receipt_ids { diff --git a/chain/chain/src/runtime/mod.rs b/chain/chain/src/runtime/mod.rs index 401a462ba93..42f1f267aa1 100644 --- a/chain/chain/src/runtime/mod.rs +++ b/chain/chain/src/runtime/mod.rs @@ -640,7 +640,7 @@ impl RuntimeAdapter for NightshadeRuntime { if let Some(state_root) = state_root { let shard_uid = - self.account_id_to_shard_uid(&transaction.transaction.signer_id, epoch_id)?; + self.account_id_to_shard_uid(transaction.transaction.signer_id(), epoch_id)?; let mut state_update = self.tries.new_trie_update(shard_uid, state_root); match verify_and_charge_transaction( diff --git a/chain/chain/src/runtime/tests.rs b/chain/chain/src/runtime/tests.rs index c5a3b8414ab..c5d76004440 100644 --- a/chain/chain/src/runtime/tests.rs +++ b/chain/chain/src/runtime/tests.rs @@ -59,6 +59,7 @@ fn stake( vec![Action::Stake(Box::new(StakeAction { stake, public_key: sender.public_key() }))], // runtime does not validate block history CryptoHash::default(), + 0 ) } @@ -338,7 +339,7 @@ impl TestEnv { let shard_layout = self.epoch_manager.get_shard_layout_from_prev_block(&new_hash).unwrap(); let mut new_receipts = HashMap::<_, Vec>::new(); for receipt in all_receipts { - let shard_id = account_id_to_shard_id(&receipt.receiver_id, &shard_layout); + let shard_id = account_id_to_shard_id(receipt.receiver_id(), &shard_layout); new_receipts.entry(shard_id).or_default().push(receipt); } self.last_receipts = new_receipts; @@ -1385,6 +1386,7 @@ fn test_delete_account_after_unstake() { })], // runtime does not validate block history CryptoHash::default(), + 0 ); env.step_default(vec![delete_account_transaction]); for _ in 15..=17 { @@ -1476,6 +1478,7 @@ fn test_trie_and_flat_state_equality() { vec![Action::Transfer(TransferAction { deposit: 10 })], // runtime does not validate block history CryptoHash::default(), + 0, ); env.step_default(vec![transfer_tx]); for _ in 1..=5 { @@ -1643,7 +1646,7 @@ fn prepare_transactions( .chain_store() .check_transaction_validity_period( &chain.get_block_header(&env.head.prev_block_hash).unwrap(), - &tx.transaction.block_hash, + tx.transaction.block_hash(), chain.transaction_validity_period, ) .is_ok() diff --git a/chain/chain/src/store.rs b/chain/chain/src/store.rs index e80a6c16dbc..ec5a659139f 100644 --- a/chain/chain/src/store.rs +++ b/chain/chain/src/store.rs @@ -381,12 +381,12 @@ fn filter_incoming_receipts_for_shard( let ReceiptProof(receipts, shard_proof) = receipt_proof.clone(); for receipt in receipts { let receiver_shard_id = - account_id_to_shard_id(&receipt.receiver_id, target_shard_layout); + account_id_to_shard_id(receipt.receiver_id(), target_shard_layout); if receiver_shard_id == target_shard_id { - tracing::trace!(target: "chain", receipt_id=?receipt.receipt_id, "including receipt"); + tracing::trace!(target: "chain", receipt_id=?receipt.receipt_id(), "including receipt"); filtered_receipts.push(receipt); } else { - tracing::trace!(target: "chain", receipt_id=?receipt.receipt_id, "excluding receipt"); + tracing::trace!(target: "chain", receipt_id=?receipt.receipt_id(), "excluding receipt"); } } // TODO(resharding) adjust the shard proof accordingly @@ -687,7 +687,7 @@ impl ChainStore { shard_id: ShardId, ) -> Result<(), Error> { receipts.retain(|receipt| { - account_id_to_shard_id(&receipt.receiver_id, &shard_layout) == shard_id + account_id_to_shard_id(receipt.receiver_id(), &shard_layout) == shard_id }); Ok(()) } @@ -1975,7 +1975,7 @@ impl<'a> ChainStoreUpdate<'a> { for receipt in chunk.prev_outgoing_receipts() { self.chain_store_cache_update .receipts - .insert(receipt.receipt_id, Arc::new(receipt.clone())); + .insert(*receipt.receipt_id(), Arc::new(receipt.clone())); } self.chain_store_cache_update.chunks.insert(chunk.chunk_hash(), Arc::new(chunk)); } diff --git a/chain/chain/src/test_utils.rs b/chain/chain/src/test_utils.rs index 1027739b0f9..1cc14341f21 100644 --- a/chain/chain/src/test_utils.rs +++ b/chain/chain/src/test_utils.rs @@ -275,7 +275,7 @@ mod test { use rand::Rng; use near_primitives::hash::CryptoHash; - use near_primitives::receipt::Receipt; + use near_primitives::receipt::{Receipt, ReceiptPriority}; use near_primitives::sharding::ReceiptList; use near_primitives::types::{AccountId, NumShards}; @@ -292,7 +292,7 @@ mod test { let shard_receipts: Vec = receipts .iter() .filter(|&receipt| { - account_id_to_shard_id(&receipt.receiver_id, shard_layout) == shard_id + account_id_to_shard_id(receipt.receiver_id(), shard_layout) == shard_id }) .cloned() .collect(); @@ -304,7 +304,7 @@ mod test { fn test_build_receipt_hashes_with_num_shard(num_shards: NumShards) { let shard_layout = ShardLayout::v0(num_shards, 0); let create_receipt_from_receiver_id = - |receiver_id| Receipt::new_balance_refund(&receiver_id, 0); + |receiver_id| Receipt::new_balance_refund(&receiver_id, 0, ReceiptPriority::NoPriority); let mut rng = rand::thread_rng(); let receipts = (0..3000) .map(|_| { diff --git a/chain/chain/src/test_utils/kv_runtime.rs b/chain/chain/src/test_utils/kv_runtime.rs index 561bce24571..590586c01e3 100644 --- a/chain/chain/src/test_utils/kv_runtime.rs +++ b/chain/chain/src/test_utils/kv_runtime.rs @@ -23,7 +23,7 @@ use near_primitives::epoch_manager::ShardConfig; use near_primitives::epoch_manager::ValidatorSelectionConfig; use near_primitives::errors::{EpochError, InvalidTxError}; use near_primitives::hash::{hash, CryptoHash}; -use near_primitives::receipt::{ActionReceipt, Receipt, ReceiptEnum}; +use near_primitives::receipt::{ActionReceipt, Receipt, ReceiptEnum, ReceiptV0}; use near_primitives::shard_layout::{ShardLayout, ShardUId}; use near_primitives::sharding::{ChunkHash, ShardChunkHeader}; use near_primitives::state_part::PartId; @@ -1116,16 +1116,16 @@ impl RuntimeAdapter for KeyValueRuntime { for receipt in receipts.iter() { if let ReceiptEnum::Action(action) | ReceiptEnum::PromiseYield(action) = - &receipt.receipt + receipt.receipt() { - assert_eq!(account_id_to_shard_id(&receipt.receiver_id, self.num_shards), shard_id); - if !state.receipt_nonces.contains(&receipt.receipt_id) { - state.receipt_nonces.insert(receipt.receipt_id); + assert_eq!(account_id_to_shard_id(receipt.receiver_id(), self.num_shards), shard_id); + if !state.receipt_nonces.contains(receipt.receipt_id()) { + state.receipt_nonces.insert(*receipt.receipt_id()); if let Action::Transfer(TransferAction { deposit }) = action.actions[0] { balance_transfers.push(( receipt.get_hash(), - receipt.predecessor_id.clone(), - receipt.receiver_id.clone(), + receipt.predecessor_id().clone(), + receipt.receiver_id().clone(), deposit, 0, )); @@ -1140,36 +1140,36 @@ impl RuntimeAdapter for KeyValueRuntime { for transaction in transactions { assert_eq!( - account_id_to_shard_id(&transaction.transaction.signer_id, self.num_shards), + account_id_to_shard_id(transaction.transaction.signer_id(), self.num_shards), shard_id ); - if transaction.transaction.actions.is_empty() { + if transaction.transaction.actions().is_empty() { continue; } - if let Action::Transfer(TransferAction { deposit }) = transaction.transaction.actions[0] + if let Action::Transfer(TransferAction { deposit }) = transaction.transaction.actions()[0] { if !state.tx_nonces.contains(&AccountNonce( - transaction.transaction.receiver_id.clone(), - transaction.transaction.nonce, + transaction.transaction.receiver_id().clone(), + transaction.transaction.nonce(), )) { state.tx_nonces.insert(AccountNonce( - transaction.transaction.receiver_id.clone(), - transaction.transaction.nonce, + transaction.transaction.receiver_id().clone(), + transaction.transaction.nonce(), )); balance_transfers.push(( transaction.get_hash(), - transaction.transaction.signer_id.clone(), - transaction.transaction.receiver_id.clone(), + transaction.transaction.signer_id().clone(), + transaction.transaction.receiver_id().clone(), deposit, - transaction.transaction.nonce, + transaction.transaction.nonce(), )); } else { balance_transfers.push(( transaction.get_hash(), - transaction.transaction.signer_id.clone(), - transaction.transaction.receiver_id.clone(), + transaction.transaction.signer_id().clone(), + transaction.transaction.receiver_id().clone(), 0, - transaction.transaction.nonce, + transaction.transaction.nonce(), )); } } else { @@ -1200,7 +1200,7 @@ impl RuntimeAdapter for KeyValueRuntime { vec![] } else { assert_ne!(nonce, 0); - let receipt = Receipt { + let receipt = Receipt::V0(ReceiptV0 { predecessor_id: from.clone(), receiver_id: to.clone(), receipt_id: create_receipt_nonce(from.clone(), to.clone(), amount, nonce), @@ -1212,7 +1212,7 @@ impl RuntimeAdapter for KeyValueRuntime { input_data_ids: vec![], actions: vec![Action::Transfer(TransferAction { deposit: amount })], }), - }; + }); let receipt_hash = receipt.get_hash(); outgoing_receipts.push(receipt); vec![receipt_hash] diff --git a/chain/chain/src/validate.rs b/chain/chain/src/validate.rs index a6c5d4d4849..02e9aa8cea8 100644 --- a/chain/chain/src/validate.rs +++ b/chain/chain/src/validate.rs @@ -78,10 +78,10 @@ pub fn validate_transactions_order(transactions: &[SignedTransaction]) -> bool { let mut current_batch = 1; for tx in transactions { - let key = (&tx.transaction.signer_id, &tx.transaction.public_key); + let key = (tx.transaction.signer_id(), tx.transaction.public_key()); // Verifying nonce - let nonce = tx.transaction.nonce; + let nonce = tx.transaction.nonce(); if let Some(last_nonce) = nonces.get(&key) { if nonce <= *last_nonce { // Nonces should increase. diff --git a/chain/chunks/src/client.rs b/chain/chunks/src/client.rs index b6c233dae83..97e7b305ceb 100644 --- a/chain/chunks/src/client.rs +++ b/chain/chunks/src/client.rs @@ -134,7 +134,7 @@ impl ShardedTransactionPool { } for tx in transactions { - let signer_id = &tx.transaction.signer_id; + let signer_id = tx.transaction.signer_id(); let new_shard_uid = account_id_to_shard_uid(&signer_id, new_shard_layout); self.insert_transaction(new_shard_uid, tx); } @@ -257,8 +257,8 @@ mod tests { while let Some(group) = pool_iter.next() { while let Some(tx) = group.next() { total += 1; - let account_id = tx.transaction.signer_id; - let tx_shard_uid = account_id_to_shard_uid(&account_id, &new_shard_layout); + let account_id = tx.transaction.signer_id(); + let tx_shard_uid = account_id_to_shard_uid(account_id, &new_shard_layout); tracing::debug!("checking {account_id:?}:{tx_shard_uid} in {shard_uid}"); assert_eq!(shard_uid, tx_shard_uid); } diff --git a/chain/client/src/client.rs b/chain/client/src/client.rs index e1f6480f8d7..7249345ec61 100644 --- a/chain/client/src/client.rs +++ b/chain/client/src/client.rs @@ -973,6 +973,7 @@ impl Client { "other".parse().unwrap(), 3, prev_block_hash, + 0 ), )); if txs.storage_proof.is_none() { @@ -2065,7 +2066,7 @@ impl Client { /// Forwards given transaction to upcoming validators. fn forward_tx(&self, epoch_id: &EpochId, tx: &SignedTransaction) -> Result<(), Error> { let shard_id = - self.epoch_manager.account_id_to_shard_id(&tx.transaction.signer_id, epoch_id)?; + self.epoch_manager.account_id_to_shard_id(tx.transaction.signer_id(), epoch_id)?; // Use the header head to make sure the list of validators is as // up-to-date as possible. let head = self.chain.header_head()?; @@ -2082,7 +2083,7 @@ impl Client { if let Some(next_epoch_id) = &maybe_next_epoch_id { let next_shard_id = self .epoch_manager - .account_id_to_shard_id(&tx.transaction.signer_id, next_epoch_id)?; + .account_id_to_shard_id(tx.transaction.signer_id(), next_epoch_id)?; let validator = self.epoch_manager.get_chunk_producer( next_epoch_id, target_height, @@ -2173,7 +2174,7 @@ impl Client { // `cur_block_header`. if let Err(e) = self.chain.chain_store().check_transaction_validity_period( &cur_block_header, - &tx.transaction.block_hash, + tx.transaction.block_hash(), transaction_validity_period, ) { debug!(target: "client", ?tx, "Invalid tx: expired or from a different fork"); @@ -2194,7 +2195,7 @@ impl Client { } let shard_id = - self.epoch_manager.account_id_to_shard_id(&tx.transaction.signer_id, &epoch_id)?; + self.epoch_manager.account_id_to_shard_id(tx.transaction.signer_id(), &epoch_id)?; let care_about_shard = self.shard_tracker.care_about_shard(me, &head.last_block_hash, shard_id, true); let will_care_about_shard = diff --git a/chain/client/src/test_utils/test_env.rs b/chain/client/src/test_utils/test_env.rs index d8ef47868eb..db84e8132b7 100644 --- a/chain/client/src/test_utils/test_env.rs +++ b/chain/client/src/test_utils/test_env.rs @@ -678,6 +678,7 @@ impl TestEnv { signer, actions, tip.last_block_hash, + 0 ) } @@ -716,6 +717,7 @@ impl TestEnv { &relayer_signer, vec![Action::Delegate(Box::new(signed_delegate_action))], tip.last_block_hash, + 0 ) } diff --git a/chain/indexer/src/streamer/utils.rs b/chain/indexer/src/streamer/utils.rs index 15d559b8ac8..6c8a14c7440 100644 --- a/chain/indexer/src/streamer/utils.rs +++ b/chain/indexer/src/streamer/utils.rs @@ -27,26 +27,29 @@ pub(crate) async fn convert_transactions_sir_into_local_receipts( .map(|tx| { let cost = tx_cost( &runtime_config, - &near_primitives::transaction::Transaction { - signer_id: tx.transaction.signer_id.clone(), - public_key: tx.transaction.public_key.clone(), - nonce: tx.transaction.nonce, - receiver_id: tx.transaction.receiver_id.clone(), - block_hash: block.header.hash, - actions: tx - .transaction - .actions - .clone() - .into_iter() - .map(|action| { - near_primitives::transaction::Action::try_from(action).unwrap() - }) - .collect(), - }, + &near_primitives::transaction::Transaction::V0( + near_primitives::transaction::TransactionV0 { + signer_id: tx.transaction.signer_id.clone(), + public_key: tx.transaction.public_key.clone(), + nonce: tx.transaction.nonce, + receiver_id: tx.transaction.receiver_id.clone(), + block_hash: block.header.hash, + actions: tx + .transaction + .actions + .clone() + .into_iter() + .map(|action| { + near_primitives::transaction::Action::try_from(action).unwrap() + }) + .collect(), + }, + ), prev_block_gas_price, true, protocol_version, - ); + ) + .expect("TransactionCost returned IntegerOverflowError"); views::ReceiptView { predecessor_id: tx.transaction.signer_id.clone(), receiver_id: tx.transaction.receiver_id.clone(), @@ -56,14 +59,13 @@ pub(crate) async fn convert_transactions_sir_into_local_receipts( receipt: views::ReceiptEnumView::Action { signer_id: tx.transaction.signer_id.clone(), signer_public_key: tx.transaction.public_key.clone(), - gas_price: cost - .expect("TransactionCost returned IntegerOverflowError") - .receipt_gas_price, + gas_price: cost.receipt_gas_price, output_data_receivers: vec![], input_data_ids: vec![], actions: tx.transaction.actions.clone(), is_promise_yield: false, }, + priority: 0, } }) .collect(); diff --git a/chain/jsonrpc-primitives/src/types/transactions.rs b/chain/jsonrpc-primitives/src/types/transactions.rs index f6f0efc49c3..30d00838035 100644 --- a/chain/jsonrpc-primitives/src/types/transactions.rs +++ b/chain/jsonrpc-primitives/src/types/transactions.rs @@ -81,7 +81,7 @@ impl TransactionInfo { match self { TransactionInfo::Transaction(tx) => match tx { SignedTransaction::SignedTransaction(tx) => { - (tx.get_hash(), &tx.transaction.signer_id) + (tx.get_hash(), tx.transaction.signer_id()) } }, TransactionInfo::TransactionId { tx_hash, sender_account_id } => { diff --git a/chain/jsonrpc/src/lib.rs b/chain/jsonrpc/src/lib.rs index e81796e5261..ab7871a6919 100644 --- a/chain/jsonrpc/src/lib.rs +++ b/chain/jsonrpc/src/lib.rs @@ -658,7 +658,7 @@ impl JsonRpcHandler { ) -> Result { let tx_hash = tx.get_hash(); - let signer_account_id = tx.transaction.signer_id.clone(); + let signer_account_id = tx.transaction.signer_id().clone(); let response = self .client_sender .send_async(ProcessTxRequest { transaction: tx, is_forwarded: false, check_only }) diff --git a/chain/pool/src/lib.rs b/chain/pool/src/lib.rs index 56708b95507..9a28a374502 100644 --- a/chain/pool/src/lib.rs +++ b/chain/pool/src/lib.rs @@ -103,8 +103,8 @@ impl TransactionPool { // At this point transaction is accepted to the pool. self.total_transaction_size = new_total_transaction_size; - let signer_id = &signed_transaction.transaction.signer_id; - let signer_public_key = &signed_transaction.transaction.public_key; + let signer_id = signed_transaction.transaction.signer_id(); + let signer_public_key = signed_transaction.transaction.public_key(); self.transactions .entry(self.key(signer_id, signer_public_key)) .or_insert_with(Vec::new) @@ -134,8 +134,8 @@ impl TransactionPool { continue; } - let signer_id = &tx.transaction.signer_id; - let signer_public_key = &tx.transaction.public_key; + let signer_id = tx.transaction.signer_id(); + let signer_public_key = tx.transaction.public_key(); grouped_transactions .entry(self.key(signer_id, signer_public_key)) .or_insert_with(HashSet::new) @@ -230,7 +230,7 @@ impl<'a> TransactionGroupIterator for PoolIteratorWrapper<'a> { self.pool.last_used_key = key; let mut transactions = self.pool.transactions.remove(&key).expect("just checked existence"); - transactions.sort_by_key(|st| std::cmp::Reverse(st.transaction.nonce)); + transactions.sort_by_key(|st| std::cmp::Reverse(st.transaction.nonce())); self.sorted_groups.push_back(TransactionGroup { key, transactions, @@ -380,7 +380,7 @@ mod tests { ( prepare_transactions(&mut pool, expected_weight) .iter() - .map(|tx| tx.transaction.nonce) + .map(|tx| tx.transaction.nonce()) .collect(), pool, ) @@ -455,7 +455,7 @@ mod tests { sort_pairs(&mut nonces[..6]); assert_eq!(nonces, vec![1, 21, 2, 22, 3, 23, 24, 25, 26, 27]); let nonces: Vec = - prepare_transactions(&mut pool, 10).iter().map(|tx| tx.transaction.nonce).collect(); + prepare_transactions(&mut pool, 10).iter().map(|tx| tx.transaction.nonce()).collect(); assert_eq!(nonces, vec![28, 29, 30, 31]); } @@ -498,9 +498,9 @@ mod tests { assert_eq!(pool.len(), txs_to_check.len()); let mut pool_txs = prepare_transactions(&mut pool, txs_to_check.len() as u32); - pool_txs.sort_by_key(|tx| tx.transaction.nonce); + pool_txs.sort_by_key(|tx| tx.transaction.nonce()); let mut expected_txs = txs_to_check.to_vec(); - expected_txs.sort_by_key(|tx| tx.transaction.nonce); + expected_txs.sort_by_key(|tx| tx.transaction.nonce()); assert_eq!(pool_txs, expected_txs); } @@ -518,7 +518,7 @@ mod tests { let mut pool_iter = pool.pool_iterator(); while let Some(iter) = pool_iter.next() { while let Some(tx) = iter.next() { - if tx.transaction.nonce & 1 == 1 { + if tx.transaction.nonce() & 1 == 1 { res.push(tx); break; } @@ -527,7 +527,7 @@ mod tests { drop(pool_iter); assert_eq!(pool.len(), 0); assert_eq!(pool.transaction_size(), 0); - let mut nonces: Vec<_> = res.into_iter().map(|tx| tx.transaction.nonce).collect(); + let mut nonces: Vec<_> = res.into_iter().map(|tx| tx.transaction.nonce()).collect(); sort_pairs(&mut nonces[..4]); assert_eq!(nonces, vec![1, 21, 3, 23, 25, 27, 29, 31]); } @@ -590,7 +590,7 @@ mod tests { let txs = prepare_transactions(&mut pool, 5); assert_eq!(txs.len(), 5); nonces.sort(); - let mut new_nonces = txs.iter().map(|tx| tx.transaction.nonce).collect::>(); + let mut new_nonces = txs.iter().map(|tx| tx.transaction.nonce()).collect::>(); new_nonces.sort(); assert_ne!(nonces, new_nonces); } diff --git a/chain/rosetta-rpc/src/lib.rs b/chain/rosetta-rpc/src/lib.rs index e8be28019ed..c014e0e5464 100644 --- a/chain/rosetta-rpc/src/lib.rs +++ b/chain/rosetta-rpc/src/lib.rs @@ -650,7 +650,7 @@ async fn construction_payloads( } = operations.try_into()?; let models::ConstructionMetadata { recent_block_hash, signer_public_access_key_nonce } = metadata; - let unsigned_transaction = near_primitives::transaction::Transaction { + let unsigned_transaction = near_primitives::transaction::Transaction::V0(near_primitives::transaction::TransactionV0 { block_hash: recent_block_hash.parse().map_err(|err| { errors::ErrorKind::InvalidInput(format!( "block hash could not be parsed due to: {:?}", @@ -662,7 +662,7 @@ async fn construction_payloads( nonce: signer_public_access_key_nonce, receiver_id: receiver_account_id, actions, - }; + }); let (transaction_hash, _) = unsigned_transaction.get_hash_and_size(); @@ -727,12 +727,7 @@ async fn construction_parse( check_network_identifier(&client_addr, network_identifier).await?; - let near_primitives::transaction::Transaction { - actions, - signer_id: sender_account_id, - receiver_id: receiver_account_id, - .. - } = if signed { + let transaction = if signed { near_primitives::transaction::SignedTransaction::try_from_slice(&transaction.into_inner()) .map_err(|err| { errors::ErrorKind::InvalidInput(format!( @@ -752,10 +747,10 @@ async fn construction_parse( }; let account_identifier_signers = - if signed { vec![sender_account_id.clone().into()] } else { vec![] }; + if signed { vec![transaction.signer_id().clone().into()] } else { vec![] }; let near_actions = - crate::adapters::NearActions { sender_account_id, receiver_account_id, actions }; + crate::adapters::NearActions { sender_account_id: transaction.signer_id().clone(), receiver_account_id: transaction.receiver_id().clone(), actions: transaction.take_actions() }; Ok(Json(models::ConstructionParseResponse { account_identifier_signers, diff --git a/core/primitives/benches/serialization.rs b/core/primitives/benches/serialization.rs index c00064c6516..fed4d75128e 100644 --- a/core/primitives/benches/serialization.rs +++ b/core/primitives/benches/serialization.rs @@ -11,7 +11,7 @@ use near_primitives::block::{genesis_chunks, Block}; use near_primitives::hash::CryptoHash; use near_primitives::merkle::combine_hash; use near_primitives::test_utils::account_new; -use near_primitives::transaction::{Action, SignedTransaction, Transaction, TransferAction}; +use near_primitives::transaction::{Action, SignedTransaction, Transaction, TransactionV0, TransferAction}; use near_primitives::types::{EpochId, StateRoot}; use near_primitives::validator_signer::InMemoryValidatorSigner; use near_primitives::version::PROTOCOL_VERSION; @@ -25,14 +25,14 @@ fn create_transaction() -> SignedTransaction { } SignedTransaction::new( Signature::empty(KeyType::ED25519), - Transaction { + Transaction::V0(TransactionV0 { signer_id: "123213123123".parse().unwrap(), public_key: PublicKey::empty(KeyType::ED25519), nonce: 123, receiver_id: "1231231232131".parse().unwrap(), block_hash: Default::default(), actions, - }, + }), ) } diff --git a/core/primitives/src/receipt.rs b/core/primitives/src/receipt.rs index 284196c2859..4950bcd9b5b 100644 --- a/core/primitives/src/receipt.rs +++ b/core/primitives/src/receipt.rs @@ -10,7 +10,7 @@ use serde_with::serde_as; use std::borrow::Borrow; use std::collections::HashMap; use std::fmt; -use std::io; +use std::io::{self, BufRead, BufReader, Read}; use std::io::{Error, ErrorKind}; /// The outgoing (egress) data which will be transformed @@ -43,7 +43,7 @@ pub struct DataReceiver { serde::Serialize, serde::Deserialize, )] -pub struct Receipt { +pub struct ReceiptV0 { /// An issuer account_id of a particular receipt. /// `predecessor_id` could be either `Transaction` `signer_id` or intermediate contract's `account_id`. pub predecessor_id: AccountId, @@ -55,34 +55,215 @@ pub struct Receipt { pub receipt: ReceiptEnum, } +#[derive( + BorshSerialize, + BorshDeserialize, + Debug, + PartialEq, + Eq, + Clone, + serde::Serialize, + serde::Deserialize, +)] +pub struct ReceiptV1 { + /// An issuer account_id of a particular receipt. + /// `predecessor_id` could be either `Transaction` `signer_id` or intermediate contract's `account_id`. + pub predecessor_id: AccountId, + /// `receiver_id` is a receipt destination. + pub receiver_id: AccountId, + /// An unique id for the receipt + pub receipt_id: CryptoHash, + /// A receipt type + pub receipt: ReceiptEnum, + /// Priority of a receipt + pub priority: u64, +} + +#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)] +pub enum Receipt { + V0(ReceiptV0), + V1(ReceiptV1), +} + +impl BorshSerialize for Receipt { + fn serialize(&self, writer: &mut W) -> io::Result<()> { + match self { + Receipt::V0(receipt) => receipt.serialize(writer), + Receipt::V1(receipt) => { + BorshSerialize::serialize(&1_u8, writer)?; + receipt.serialize(writer) + } + } + } +} + +impl BorshDeserialize for Receipt { + /// Deserialize based on the first byte of the buffer. If the first byte is 0, it is a V0 + /// Otherwise, it is a V1. For V0, we do backward compatible deserialization by deserializing + /// the entire stream into V0. For V1, we consume the first byte and then deserialize the rest + /// No conflict is possible because the first field of Receipt is an `AccountId` which starts + /// with a `usize` but can only be at most 64 bytes long, so the highest byte is always 0. + fn deserialize_reader(reader: &mut R) -> std::io::Result { + // Note: the following implementation is inefficient because it copies data twice. + // and should be replaced once the protocol switches to the new receipt format entirely. + let mut buf_reader = BufReader::new(reader); + let buffer = buf_reader.fill_buf()?; // Fill the buffer + if buffer.is_empty() { + return Err(Error::new(ErrorKind::UnexpectedEof, "No data to read")); + } else { + let first_byte = buffer[0]; + if first_byte == 0 { + let receipt = ReceiptV0::deserialize_reader(&mut buf_reader)?; + Ok(Receipt::V0(receipt)) + } else if first_byte == 1 { + let _ = buf_reader.consume(1); // Consume the first byte + let receipt = ReceiptV1::deserialize_reader(&mut buf_reader)?; + Ok(Receipt::V1(receipt)) + } else { + Err(Error::new(ErrorKind::InvalidData, "Invalid version")) + } + } + } +} + +pub enum ReceiptPriority { + /// Used in ReceiptV1 + Priority(u64), + /// Used in ReceiptV0 + NoPriority, +} + +impl ReceiptPriority { + pub fn value(&self) -> u64 { + match self { + ReceiptPriority::Priority(value) => *value, + ReceiptPriority::NoPriority => 0, + } + } +} + impl Borrow for Receipt { fn borrow(&self) -> &CryptoHash { - &self.receipt_id + match self { + Receipt::V0(receipt) => &receipt.receipt_id, + Receipt::V1(receipt) => &receipt.receipt_id, + } } } impl Receipt { + pub fn receiver_id(&self) -> &AccountId { + match self { + Receipt::V0(receipt) => &receipt.receiver_id, + Receipt::V1(receipt) => &receipt.receiver_id, + } + } + + pub fn set_receiver_id(&mut self, receiver_id: AccountId) { + match self { + Receipt::V0(receipt) => receipt.receiver_id = receiver_id, + Receipt::V1(receipt) => receipt.receiver_id = receiver_id, + } + } + + pub fn predecessor_id(&self) -> &AccountId { + match self { + Receipt::V0(receipt) => &receipt.predecessor_id, + Receipt::V1(receipt) => &receipt.predecessor_id, + } + } + + pub fn set_predecessor_id(&mut self, predecessor_id: AccountId) { + match self { + Receipt::V0(receipt) => receipt.predecessor_id = predecessor_id, + Receipt::V1(receipt) => receipt.predecessor_id = predecessor_id, + } + } + + pub fn receipt(&self) -> &ReceiptEnum { + match self { + Receipt::V0(receipt) => &receipt.receipt, + Receipt::V1(receipt) => &receipt.receipt, + } + } + + pub fn receipt_mut(&mut self) -> &mut ReceiptEnum { + match self { + Receipt::V0(receipt) => &mut receipt.receipt, + Receipt::V1(receipt) => &mut receipt.receipt, + } + } + + pub fn take_receipt(self) -> ReceiptEnum { + match self { + Receipt::V0(receipt) => receipt.receipt, + Receipt::V1(receipt) => receipt.receipt, + } + } + + pub fn receipt_id(&self) -> &CryptoHash { + match self { + Receipt::V0(receipt) => &receipt.receipt_id, + Receipt::V1(receipt) => &receipt.receipt_id, + } + } + + pub fn set_receipt_id(&mut self, receipt_id: CryptoHash) { + match self { + Receipt::V0(receipt) => receipt.receipt_id = receipt_id, + Receipt::V1(receipt) => receipt.receipt_id = receipt_id, + } + } + + pub fn priority(&self) -> ReceiptPriority { + match self { + Receipt::V0(_) => ReceiptPriority::NoPriority, + Receipt::V1(receipt) => ReceiptPriority::Priority(receipt.priority), + } + } + /// It's not a content hash, but receipt_id is unique. pub fn get_hash(&self) -> CryptoHash { - self.receipt_id + *self.receipt_id() } /// Generates a receipt with a transfer from system for a given balance without a receipt_id. - /// This should be used for token refunds instead of gas refunds. It doesn't refund the - /// allowance of the access key. For gas refunds use `new_gas_refund`. - pub fn new_balance_refund(receiver_id: &AccountId, refund: Balance) -> Self { - Receipt { - predecessor_id: "system".parse().unwrap(), - receiver_id: receiver_id.clone(), - receipt_id: CryptoHash::default(), - - receipt: ReceiptEnum::Action(ActionReceipt { - signer_id: "system".parse().unwrap(), - signer_public_key: PublicKey::empty(KeyType::ED25519), - gas_price: 0, - output_data_receivers: vec![], - input_data_ids: vec![], - actions: vec![Action::Transfer(TransferAction { deposit: refund })], + /// This should be used for token refunds instead of gas refunds. It inherits priority from the parent receipt. + /// It doesn't refund the allowance of the access key. For gas refunds use `new_gas_refund`. + pub fn new_balance_refund( + receiver_id: &AccountId, + refund: Balance, + priority: ReceiptPriority, + ) -> Self { + match priority { + ReceiptPriority::Priority(priority) => Receipt::V1(ReceiptV1 { + predecessor_id: "system".parse().unwrap(), + receiver_id: receiver_id.clone(), + receipt_id: CryptoHash::default(), + + receipt: ReceiptEnum::Action(ActionReceipt { + signer_id: "system".parse().unwrap(), + signer_public_key: PublicKey::empty(KeyType::ED25519), + gas_price: 0, + output_data_receivers: vec![], + input_data_ids: vec![], + actions: vec![Action::Transfer(TransferAction { deposit: refund })], + }), + priority, + }), + ReceiptPriority::NoPriority => Receipt::V0(ReceiptV0 { + predecessor_id: "system".parse().unwrap(), + receiver_id: receiver_id.clone(), + receipt_id: CryptoHash::default(), + + receipt: ReceiptEnum::Action(ActionReceipt { + signer_id: "system".parse().unwrap(), + signer_public_key: PublicKey::empty(KeyType::ED25519), + gas_price: 0, + output_data_receivers: vec![], + input_data_ids: vec![], + actions: vec![Action::Transfer(TransferAction { deposit: refund })], + }), }), } } @@ -91,25 +272,44 @@ impl Receipt { /// receipt_id. It contains `signer_id` and `signer_public_key` to indicate this is a gas /// refund. The execution of this receipt will try to refund the allowance of the /// access key with the given public key. + /// Gas refund does not inherit priority from its parent receipt and has no priority associated with it /// NOTE: The access key may be replaced by the owner, so the execution can't rely that the /// access key is the same and it should use best effort for the refund. pub fn new_gas_refund( receiver_id: &AccountId, refund: Balance, signer_public_key: PublicKey, + priority: ReceiptPriority, ) -> Self { - Receipt { - predecessor_id: "system".parse().unwrap(), - receiver_id: receiver_id.clone(), - receipt_id: CryptoHash::default(), - - receipt: ReceiptEnum::Action(ActionReceipt { - signer_id: receiver_id.clone(), - signer_public_key, - gas_price: 0, - output_data_receivers: vec![], - input_data_ids: vec![], - actions: vec![Action::Transfer(TransferAction { deposit: refund })], + match priority { + ReceiptPriority::Priority(priority) => Receipt::V1(ReceiptV1 { + predecessor_id: "system".parse().unwrap(), + receiver_id: receiver_id.clone(), + receipt_id: CryptoHash::default(), + + receipt: ReceiptEnum::Action(ActionReceipt { + signer_id: receiver_id.clone(), + signer_public_key, + gas_price: 0, + output_data_receivers: vec![], + input_data_ids: vec![], + actions: vec![Action::Transfer(TransferAction { deposit: refund })], + }), + priority, + }), + ReceiptPriority::NoPriority => Receipt::V0(ReceiptV0 { + predecessor_id: "system".parse().unwrap(), + receiver_id: receiver_id.clone(), + receipt_id: CryptoHash::default(), + + receipt: ReceiptEnum::Action(ActionReceipt { + signer_id: receiver_id.clone(), + signer_public_key, + gas_price: 0, + output_data_receivers: vec![], + input_data_ids: vec![], + actions: vec![Action::Transfer(TransferAction { deposit: refund })], + }), }), } } diff --git a/core/primitives/src/state_record.rs b/core/primitives/src/state_record.rs index 3b62a361906..1dab335f550 100644 --- a/core/primitives/src/state_record.rs +++ b/core/primitives/src/state_record.rs @@ -179,7 +179,7 @@ pub fn state_record_to_account_id(state_record: &StateRecord) -> &AccountId { | StateRecord::ReceivedData { account_id, .. } | StateRecord::Data { account_id, .. } => account_id, StateRecord::PostponedReceipt(receipt) | StateRecord::DelayedReceipt(receipt) => { - &receipt.receiver_id + receipt.receiver_id() } } } diff --git a/core/primitives/src/test_utils.rs b/core/primitives/src/test_utils.rs index 468657b5b59..affa017a3c9 100644 --- a/core/primitives/src/test_utils.rs +++ b/core/primitives/src/test_utils.rs @@ -9,9 +9,7 @@ use crate::merkle::PartialMerkleTree; use crate::num_rational::Ratio; use crate::sharding::{ShardChunkHeader, ShardChunkHeaderV3}; use crate::transaction::{ - Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction, - DeployContractAction, FunctionCallAction, SignedTransaction, StakeAction, Transaction, - TransferAction, + Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction, DeployContractAction, FunctionCallAction, SignedTransaction, StakeAction, Transaction, TransactionV1, TransferAction }; use crate::types::{AccountId, Balance, EpochId, EpochInfoProvider, Gas, Nonce}; use crate::validator_signer::{InMemoryValidatorSigner, ValidatorSigner}; @@ -36,8 +34,23 @@ impl Transaction { receiver_id: AccountId, nonce: Nonce, block_hash: CryptoHash, + priority_fee: u64 ) -> Self { - Self { signer_id, public_key, nonce, receiver_id, block_hash, actions: vec![] } + Transaction::V1(TransactionV1 { signer_id, public_key, nonce, receiver_id, block_hash, actions: vec![], priority_fee }) + } + + pub fn actions_mut(&mut self) -> &mut Vec { + match self { + Transaction::V0(tx) => &mut tx.actions, + Transaction::V1(tx) => &mut tx.actions, + } + } + + pub fn nonce_mut(&mut self) -> &mut Nonce { + match self { + Transaction::V0(tx) => &mut tx.nonce, + Transaction::V1(tx) => &mut tx.nonce, + } } pub fn sign(self, signer: &dyn Signer) -> SignedTransaction { @@ -46,12 +59,12 @@ impl Transaction { } pub fn create_account(mut self) -> Self { - self.actions.push(Action::CreateAccount(CreateAccountAction {})); + self.actions_mut().push(Action::CreateAccount(CreateAccountAction {})); self } pub fn deploy_contract(mut self, code: Vec) -> Self { - self.actions.push(Action::DeployContract(DeployContractAction { code })); + self.actions_mut().push(Action::DeployContract(DeployContractAction { code })); self } @@ -62,7 +75,7 @@ impl Transaction { gas: Gas, deposit: Balance, ) -> Self { - self.actions.push(Action::FunctionCall(Box::new(FunctionCallAction { + self.actions_mut().push(Action::FunctionCall(Box::new(FunctionCallAction { method_name, args, gas, @@ -72,30 +85,32 @@ impl Transaction { } pub fn transfer(mut self, deposit: Balance) -> Self { - self.actions.push(Action::Transfer(TransferAction { deposit })); + self.actions_mut().push(Action::Transfer(TransferAction { deposit })); self } pub fn stake(mut self, stake: Balance, public_key: PublicKey) -> Self { - self.actions.push(Action::Stake(Box::new(StakeAction { stake, public_key }))); + self.actions_mut().push(Action::Stake(Box::new(StakeAction { stake, public_key }))); self } pub fn add_key(mut self, public_key: PublicKey, access_key: AccessKey) -> Self { - self.actions.push(Action::AddKey(Box::new(AddKeyAction { public_key, access_key }))); + self.actions_mut().push(Action::AddKey(Box::new(AddKeyAction { public_key, access_key }))); self } pub fn delete_key(mut self, public_key: PublicKey) -> Self { - self.actions.push(Action::DeleteKey(Box::new(DeleteKeyAction { public_key }))); + self.actions_mut().push(Action::DeleteKey(Box::new(DeleteKeyAction { public_key }))); self } pub fn delete_account(mut self, beneficiary_id: AccountId) -> Self { - self.actions.push(Action::DeleteAccount(DeleteAccountAction { beneficiary_id })); + self.actions_mut().push(Action::DeleteAccount(DeleteAccountAction { beneficiary_id })); self } } +/// This block implements a set of helper functions to create transactions for testing purposes. +/// Therefore, `TransactionV1` is used to create transactions. impl SignedTransaction { pub fn from_actions( nonce: Nonce, @@ -104,15 +119,17 @@ impl SignedTransaction { signer: &dyn Signer, actions: Vec, block_hash: CryptoHash, + priority_fee: u64, ) -> Self { - Transaction { + Transaction::V1(TransactionV1 { nonce, signer_id, public_key: signer.public_key(), receiver_id, block_hash, actions, - } + priority_fee + }) .sign(signer) } @@ -131,6 +148,7 @@ impl SignedTransaction { signer, vec![Action::Transfer(TransferAction { deposit })], block_hash, + 0 ) } @@ -149,6 +167,7 @@ impl SignedTransaction { signer, vec![Action::Stake(Box::new(StakeAction { stake, public_key }))], block_hash, + 0 ) } @@ -175,6 +194,7 @@ impl SignedTransaction { Action::Transfer(TransferAction { deposit: amount }), ], block_hash, + 0 ) } @@ -203,6 +223,7 @@ impl SignedTransaction { Action::DeployContract(DeployContractAction { code }), ], block_hash, + 0 ) } @@ -229,6 +250,7 @@ impl SignedTransaction { deposit, }))], block_hash, + 0 ) } @@ -247,6 +269,7 @@ impl SignedTransaction { signer, vec![Action::DeleteAccount(DeleteAccountAction { beneficiary_id })], block_hash, + 0 ) } @@ -258,6 +281,7 @@ impl SignedTransaction { &EmptySigner {}, vec![], block_hash, + 0 ) } } diff --git a/core/primitives/src/transaction.rs b/core/primitives/src/transaction.rs index 1a7759c95f9..6cfa131c086 100644 --- a/core/primitives/src/transaction.rs +++ b/core/primitives/src/transaction.rs @@ -13,6 +13,7 @@ use serde::ser::Error as EncodeError; use std::borrow::Borrow; use std::fmt; use std::hash::{Hash, Hasher}; +use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Write}; #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] pub use crate::action::NonrefundableStorageTransferAction; @@ -24,7 +25,7 @@ pub use crate::action::{ pub type LogEntry = String; #[derive(BorshSerialize, BorshDeserialize, serde::Serialize, PartialEq, Eq, Debug, Clone)] -pub struct Transaction { +pub struct TransactionV0 { /// An account on which behalf transaction is signed pub signer_id: AccountId, /// A public key of the access key which was used to sign an account. @@ -41,6 +42,26 @@ pub struct Transaction { pub actions: Vec, } +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] +pub struct TransactionV1 { + /// An account on which behalf transaction is signed + pub signer_id: AccountId, + /// A public key of the access key which was used to sign an account. + /// Access key holds permissions for calling certain kinds of actions. + pub public_key: PublicKey, + /// Nonce is used to determine order of transaction in the pool. + /// It increments for a combination of `signer_id` and `public_key` + pub nonce: Nonce, + /// Receiver account for this transaction + pub receiver_id: AccountId, + /// The hash of the block in the blockchain on top of which the given transaction is valid + pub block_hash: CryptoHash, + /// A list of actions to be applied + pub actions: Vec, + /// Priority fee. Unit is 10^12 yotcoNEAR + pub priority_fee: u64, +} + impl Transaction { /// Computes a hash of the transaction for signing and size of serialized transaction pub fn get_hash_and_size(&self) -> (CryptoHash, u64) { @@ -49,6 +70,112 @@ impl Transaction { } } +#[derive(Eq, PartialEq, Debug, Clone)] +pub enum Transaction { + V0(TransactionV0), + V1(TransactionV1), +} + +impl Transaction { + pub fn signer_id(&self) -> &AccountId { + match self { + Transaction::V0(tx) => &tx.signer_id, + Transaction::V1(tx) => &tx.signer_id, + } + } + + pub fn receiver_id(&self) -> &AccountId { + match self { + Transaction::V0(tx) => &tx.receiver_id, + Transaction::V1(tx) => &tx.receiver_id, + } + } + + pub fn public_key(&self) -> &PublicKey { + match self { + Transaction::V0(tx) => &tx.public_key, + Transaction::V1(tx) => &tx.public_key, + } + } + + pub fn nonce(&self) -> Nonce { + match self { + Transaction::V0(tx) => tx.nonce, + Transaction::V1(tx) => tx.nonce, + } + } + + pub fn actions(&self) -> &[Action] { + match self { + Transaction::V0(tx) => &tx.actions, + Transaction::V1(tx) => &tx.actions, + } + } + + pub fn take_actions(self) -> Vec { + match self { + Transaction::V0(tx) => tx.actions, + Transaction::V1(tx) => tx.actions, + } + } + + pub fn block_hash(&self) -> &CryptoHash { + match self { + Transaction::V0(tx) => &tx.block_hash, + Transaction::V1(tx) => &tx.block_hash, + } + } + + pub fn priority_fee(&self) -> Option { + match self { + Transaction::V0(_) => None, + Transaction::V1(tx) => Some(tx.priority_fee), + } + } +} + +impl BorshSerialize for Transaction { + fn serialize(&self, writer: &mut W) -> Result<(), Error> { + match self { + Transaction::V0(tx) => tx.serialize(writer)?, + Transaction::V1(tx) => { + BorshSerialize::serialize(&1_u8, writer)?; + tx.serialize(writer)?; + } + } + Ok(()) + } +} + +impl BorshDeserialize for Transaction { + /// Deserialize based on the first byte of the buffer. If the first byte is 0, it is a V0 + /// Otherwise, it is a V1. For V0, we do backward compatible deserialization by deserializing + /// the entire stream into V0. For V1, we consume the first byte and then deserialize the rest + /// No conflict is possible because the first field of Transaction is an `AccountId` which starts + /// with a `usize` but can only be at most 64 bytes long, so the highest byte is always 0. + fn deserialize_reader(reader: &mut R) -> std::io::Result { + // Note: the following implementation is inefficient because it copies data twice. + // and should be replaced once the protocol switches to the new transaction format entirely. + let mut buf_reader = BufReader::new(reader); + let buffer = buf_reader.fill_buf()?; // Fill the buffer + if buffer.is_empty() { + return Err(Error::new(ErrorKind::UnexpectedEof, "No data to read")); + } else { + let first_byte = buffer[0]; + if first_byte == 0 { + let tx = TransactionV0::deserialize_reader(&mut buf_reader)?; + Ok(Transaction::V0(tx)) + } else if first_byte == 1 { + let _ = buf_reader.consume(1); // Consume the first byte + let tx = TransactionV1::deserialize_reader(&mut buf_reader)?; + Ok(Transaction::V1(tx)) + } else { + Err(Error::new(ErrorKind::InvalidData, "Invalid version")) + } + } + } +} + #[derive(BorshSerialize, BorshDeserialize, Eq, Debug, Clone)] #[borsh(init=init)] pub struct SignedTransaction { @@ -319,14 +446,14 @@ mod tests { #[test] fn test_verify_transaction() { let signer = InMemorySigner::from_random("test".parse().unwrap(), KeyType::ED25519); - let transaction = Transaction { + let transaction = Transaction::V0(TransactionV0 { signer_id: "test".parse().unwrap(), public_key: signer.public_key(), nonce: 0, receiver_id: "test".parse().unwrap(), block_hash: Default::default(), actions: vec![], - } + }) .sign(&signer); let wrong_public_key = PublicKey::from_seed(KeyType::ED25519, "wrong"); let valid_keys = vec![signer.public_key(), wrong_public_key.clone()]; @@ -345,7 +472,7 @@ mod tests { #[test] fn test_serialize_transaction() { let public_key: PublicKey = "22skMptHjFWNyuEWY22ftn2AbLPSYpmYwGJRGwpNHbTV".parse().unwrap(); - let transaction = Transaction { + let transaction = Transaction::V0(TransactionV0 { signer_id: "test.near".parse().unwrap(), public_key: public_key.clone(), nonce: 1, @@ -381,7 +508,7 @@ mod tests { beneficiary_id: "123".parse().unwrap(), }), ], - }; + }); let signed_tx = SignedTransaction::new(Signature::empty(KeyType::ED25519), transaction); let new_signed_tx = SignedTransaction::try_from_slice(&borsh::to_vec(&signed_tx).unwrap()).unwrap(); @@ -392,6 +519,9 @@ mod tests { ); } + #[test] + fn test_serialize_transaction_versions() {} + #[test] fn test_outcome_to_hashes() { let outcome = ExecutionOutcome { diff --git a/core/primitives/src/views.rs b/core/primitives/src/views.rs index 9c782e15a08..dab895e6bf1 100644 --- a/core/primitives/src/views.rs +++ b/core/primitives/src/views.rs @@ -17,7 +17,7 @@ use crate::errors::TxExecutionError; use crate::hash::{hash, CryptoHash}; use crate::merkle::{combine_hash, MerklePath}; use crate::network::PeerId; -use crate::receipt::{ActionReceipt, DataReceipt, DataReceiver, Receipt, ReceiptEnum}; +use crate::receipt::{ActionReceipt, DataReceipt, DataReceiver, Receipt, ReceiptEnum, ReceiptV1}; use crate::serialize::dec_format; use crate::sharding::{ ChunkHash, ShardChunk, ShardChunkHeader, ShardChunkHeaderInner, ShardChunkHeaderInnerV2, @@ -1318,6 +1318,7 @@ pub struct SignedTransactionView { pub nonce: Nonce, pub receiver_id: AccountId, pub actions: Vec, + pub priority_fee: u64, pub signature: Signature, pub hash: CryptoHash, } @@ -1325,19 +1326,17 @@ pub struct SignedTransactionView { impl From for SignedTransactionView { fn from(signed_tx: SignedTransaction) -> Self { let hash = signed_tx.get_hash(); + let transaction = signed_tx.transaction; + let priority_fee = transaction.priority_fee().unwrap_or_default(); SignedTransactionView { - signer_id: signed_tx.transaction.signer_id, - public_key: signed_tx.transaction.public_key, - nonce: signed_tx.transaction.nonce, - receiver_id: signed_tx.transaction.receiver_id, - actions: signed_tx - .transaction - .actions - .into_iter() - .map(|action| action.into()) - .collect(), + signer_id: transaction.signer_id().clone(), + public_key: transaction.public_key().clone(), + nonce: transaction.nonce(), + receiver_id: transaction.receiver_id().clone(), + actions: transaction.take_actions().into_iter().map(|action| action.into()).collect(), signature: signed_tx.signature, hash, + priority_fee, } } } @@ -1898,6 +1897,7 @@ pub struct ReceiptView { pub receipt_id: CryptoHash, pub receipt: ReceiptEnumView, + pub priority: u64, } #[derive( @@ -1956,14 +1956,15 @@ fn default_is_promise() -> bool { impl From for ReceiptView { fn from(receipt: Receipt) -> Self { - let is_promise_yield = matches!(&receipt.receipt, ReceiptEnum::PromiseYield(_)); - let is_promise_resume = matches!(&receipt.receipt, ReceiptEnum::PromiseResume(_)); + let is_promise_yield = matches!(receipt.receipt(), ReceiptEnum::PromiseYield(_)); + let is_promise_resume = matches!(receipt.receipt(), ReceiptEnum::PromiseResume(_)); + let priority = receipt.priority().value(); ReceiptView { - predecessor_id: receipt.predecessor_id, - receiver_id: receipt.receiver_id, - receipt_id: receipt.receipt_id, - receipt: match receipt.receipt { + predecessor_id: receipt.predecessor_id().clone(), + receiver_id: receipt.receiver_id().clone(), + receipt_id: *receipt.receipt_id(), + receipt: match receipt.take_receipt() { ReceiptEnum::Action(action_receipt) | ReceiptEnum::PromiseYield(action_receipt) => { ReceiptEnumView::Action { signer_id: action_receipt.signer_id, @@ -1994,6 +1995,7 @@ impl From for ReceiptView { } } }, + priority, } } } @@ -2002,7 +2004,7 @@ impl TryFrom for Receipt { type Error = Box; fn try_from(receipt_view: ReceiptView) -> Result { - Ok(Receipt { + Ok(Receipt::V1(ReceiptV1 { predecessor_id: receipt_view.predecessor_id, receiver_id: receipt_view.receiver_id, receipt_id: receipt_view.receipt_id, @@ -2050,7 +2052,8 @@ impl TryFrom for Receipt { } } }, - }) + priority: receipt_view.priority, + })) } } diff --git a/core/store/benches/finalize_bench.rs b/core/store/benches/finalize_bench.rs index f8f6eb0772d..40565b155c5 100644 --- a/core/store/benches/finalize_bench.rs +++ b/core/store/benches/finalize_bench.rs @@ -21,7 +21,7 @@ use near_chunks::ShardsManager; use near_crypto::{InMemorySigner, KeyType, Signer}; use near_primitives::hash::CryptoHash; use near_primitives::merkle::{merklize, MerklePathItem}; -use near_primitives::receipt::{ActionReceipt, DataReceipt, Receipt, ReceiptEnum}; +use near_primitives::receipt::{ActionReceipt, DataReceipt, Receipt, ReceiptEnum, ReceiptV0}; use near_primitives::reed_solomon::ReedSolomonWrapper; use near_primitives::shard_layout::ShardLayout; use near_primitives::sharding::{ @@ -138,7 +138,7 @@ fn create_action_receipt( actions: Vec, input_data_ids: Vec, ) -> Receipt { - Receipt { + Receipt::V0(ReceiptV0 { predecessor_id: account_id.clone(), receiver_id: account_id.clone(), receipt_id: CryptoHash::hash_borsh(actions.clone()), @@ -150,16 +150,16 @@ fn create_action_receipt( input_data_ids, actions, }), - } + }) } fn create_data_receipt(account_id: &AccountId, data_id: CryptoHash, data_size: usize) -> Receipt { - Receipt { + Receipt::V0(ReceiptV0 { predecessor_id: account_id.clone(), receiver_id: account_id.clone(), receipt_id: CryptoHash::hash_borsh(data_id), receipt: ReceiptEnum::Data(DataReceipt { data_id, data: Some(vec![77u8; data_size]) }), - } + }) } fn create_shard_chunk( diff --git a/core/store/src/genesis/state_applier.rs b/core/store/src/genesis/state_applier.rs index 4a680bfc020..e0c4a187883 100644 --- a/core/store/src/genesis/state_applier.rs +++ b/core/store/src/genesis/state_applier.rs @@ -269,11 +269,11 @@ impl GenesisStateApplier { "processing postponed receipts…" ); for receipt in postponed_receipts { - let account_id = &receipt.receiver_id; + let account_id = receipt.receiver_id(); // Logic similar to `apply_receipt` - match receipt.receipt { - ReceiptEnum::Action(ref action_receipt) => { + match receipt.receipt() { + ReceiptEnum::Action(action_receipt) => { let mut pending_data_count: u32 = 0; for data_id in &action_receipt.input_data_ids { storage.modify(|state_update| { @@ -287,7 +287,7 @@ impl GenesisStateApplier { receiver_id: account_id.clone(), data_id: *data_id, }, - &receipt.receipt_id, + receipt.receipt_id(), ) } }); @@ -300,7 +300,7 @@ impl GenesisStateApplier { state_update, TrieKey::PendingDataCount { receiver_id: account_id.clone(), - receipt_id: receipt.receipt_id, + receipt_id: *receipt.receipt_id(), }, &pending_data_count, ); diff --git a/core/store/src/lib.rs b/core/store/src/lib.rs index 96ece091992..3cc7fea15f0 100644 --- a/core/store/src/lib.rs +++ b/core/store/src/lib.rs @@ -782,10 +782,10 @@ pub fn has_received_data( } pub fn set_postponed_receipt(state_update: &mut TrieUpdate, receipt: &Receipt) { - assert!(matches!(receipt.receipt, ReceiptEnum::Action(_))); + assert!(matches!(receipt.receipt(), ReceiptEnum::Action(_))); let key = TrieKey::PostponedReceipt { - receiver_id: receipt.receiver_id.clone(), - receipt_id: receipt.receipt_id, + receiver_id: receipt.receiver_id().clone(), + receipt_id: *receipt.receipt_id(), }; set(state_update, key, receipt); } @@ -865,11 +865,11 @@ pub fn enqueue_promise_yield_timeout( pub fn set_promise_yield_receipt(state_update: &mut TrieUpdate, receipt: &Receipt) { assert!(cfg!(feature = "yield_resume")); - match &receipt.receipt { + match receipt.receipt() { ReceiptEnum::PromiseYield(ref action_receipt) => { assert!(action_receipt.input_data_ids.len() == 1); let key = TrieKey::PromiseYieldReceipt { - receiver_id: receipt.receiver_id.clone(), + receiver_id: receipt.receiver_id().clone(), data_id: action_receipt.input_data_ids[0], }; set(state_update, key, receipt); diff --git a/core/store/src/test_utils.rs b/core/store/src/test_utils.rs index 3aab48d8d6f..3517e7a0ea1 100644 --- a/core/store/src/test_utils.rs +++ b/core/store/src/test_utils.rs @@ -10,7 +10,7 @@ use crate::{ use itertools::Itertools; use near_primitives::account::id::AccountId; use near_primitives::hash::CryptoHash; -use near_primitives::receipt::{DataReceipt, PromiseYieldTimeout, Receipt, ReceiptEnum}; +use near_primitives::receipt::{DataReceipt, PromiseYieldTimeout, Receipt, ReceiptEnum, ReceiptV1}; use near_primitives::shard_layout::{ShardUId, ShardVersion}; use near_primitives::state::FlatStateValue; use near_primitives::trie_key::TrieKey; @@ -266,12 +266,13 @@ pub fn gen_receipts(rng: &mut impl Rng, max_size: usize) -> Vec { let accounts = gen_accounts_from_alphabet(rng, 1, max_size, &alphabet); accounts .iter() - .map(|account_id| Receipt { + .map(|account_id| Receipt::V1(ReceiptV1 { predecessor_id: account_id.clone(), receiver_id: account_id.clone(), receipt_id: CryptoHash::default(), receipt: ReceiptEnum::Data(DataReceipt { data_id: CryptoHash::default(), data: None }), - }) + priority: 0, + })) .collect() } diff --git a/core/store/src/trie/resharding.rs b/core/store/src/trie/resharding.rs index 0d71dcec6ac..88f56d8fd5d 100644 --- a/core/store/src/trie/resharding.rs +++ b/core/store/src/trie/resharding.rs @@ -263,11 +263,11 @@ fn apply_delayed_receipts_to_children_states_impl( } for receipt in insert_receipts { - let new_shard_uid: ShardUId = account_id_to_shard_uid(&receipt.receiver_id); + let new_shard_uid: ShardUId = account_id_to_shard_uid(receipt.receiver_id()); if !trie_updates.contains_key(&new_shard_uid) { let err = format!( "Account {} is in new shard {:?} but state_roots only contains {:?}", - receipt.receiver_id, + receipt.receiver_id(), new_shard_uid, trie_updates.keys(), ); @@ -292,11 +292,11 @@ fn apply_delayed_receipts_to_children_states_impl( } for receipt in delete_receipts { - let new_shard_uid: ShardUId = account_id_to_shard_uid(&receipt.receiver_id); + let new_shard_uid: ShardUId = account_id_to_shard_uid(receipt.receiver_id()); if !trie_updates.contains_key(&new_shard_uid) { let err = format!( "Account {} is in new shard {:?} but state_roots only contains {:?}", - receipt.receiver_id, + receipt.receiver_id(), new_shard_uid, trie_updates.keys(), ); @@ -710,7 +710,7 @@ mod tests { let mut expected_receipts_by_shard: HashMap<_, _> = state_roots.iter().map(|(shard_uid, _)| (shard_uid, vec![])).collect(); for receipt in expected_all_receipts { - let shard_uid = account_id_to_shard_id(&receipt.receiver_id); + let shard_uid = account_id_to_shard_id(receipt.receiver_id()); expected_receipts_by_shard.get_mut(&shard_uid).unwrap().push(receipt.clone()); } assert_eq!(expected_receipts_by_shard, receipts_by_shard); diff --git a/genesis-tools/genesis-csv-to-json/src/csv_parser.rs b/genesis-tools/genesis-csv-to-json/src/csv_parser.rs index 4a16c517e59..e717877b162 100644 --- a/genesis-tools/genesis-csv-to-json/src/csv_parser.rs +++ b/genesis-tools/genesis-csv-to-json/src/csv_parser.rs @@ -6,6 +6,7 @@ use near_crypto::{KeyType, PublicKey}; use near_network::types::PeerInfo; use near_primitives::account::{AccessKey, AccessKeyPermission, Account, FunctionCallPermission}; use near_primitives::hash::{hash, CryptoHash}; +use near_primitives::receipt::ReceiptV0; use near_primitives::receipt::{ActionReceipt, Receipt, ReceiptEnum}; use near_primitives::state_record::StateRecord; use near_primitives::transaction::{Action, FunctionCallAction}; @@ -253,7 +254,7 @@ fn account_records(row: &Row, gas_price: Balance) -> Vec { } _ => unimplemented!(), }; - let receipt = Receipt { + let receipt = Receipt::V0(ReceiptV0 { predecessor_id: row.account_id.clone(), receiver_id: row.account_id.clone(), // `receipt_id` can be anything as long as it is unique. @@ -273,7 +274,7 @@ fn account_records(row: &Row, gas_price: Balance) -> Vec { deposit: 0, }))], }), - }; + }); res.push(StateRecord::PostponedReceipt(Box::new(receipt))); } res diff --git a/integration-tests/src/tests/client/benchmarks.rs b/integration-tests/src/tests/client/benchmarks.rs index 1d865d4c6ca..323988754c9 100644 --- a/integration-tests/src/tests/client/benchmarks.rs +++ b/integration-tests/src/tests/client/benchmarks.rs @@ -41,6 +41,7 @@ fn benchmark_large_chunk_production_time() { &signer, vec![Action::DeployContract(DeployContractAction { code: vec![92; tx_size] })], last_block_hash, + 0 ); assert_eq!(env.clients[0].process_tx(tx, false, false), ProcessTxResponse::ValidTx); } diff --git a/integration-tests/src/tests/client/cold_storage.rs b/integration-tests/src/tests/client/cold_storage.rs index 57655f5c68a..3e625de9af9 100644 --- a/integration-tests/src/tests/client/cold_storage.rs +++ b/integration-tests/src/tests/client/cold_storage.rs @@ -87,7 +87,7 @@ fn create_tx_deploy_contract( let code = near_test_contracts::rs_contract().to_vec(); let action = DeployContractAction { code }; let action = Action::DeployContract(action); - SignedTransaction::from_actions(height, test0(), test0(), signer, vec![action], block_hash) + SignedTransaction::from_actions(height, test0(), test0(), signer, vec![action], block_hash, 0) } fn create_tx_function_call( @@ -101,7 +101,7 @@ fn create_tx_function_call( gas: 100_000_000_000_000, deposit: 0, })); - SignedTransaction::from_actions(nonce, test0(), test0(), signer, vec![action], block_hash) + SignedTransaction::from_actions(nonce, test0(), test0(), signer, vec![action], block_hash, 0) } /// Deploying test contract and calling write_random_value 5 times every block for 4 epochs. diff --git a/integration-tests/src/tests/client/features/account_id_in_function_call_permission.rs b/integration-tests/src/tests/client/features/account_id_in_function_call_permission.rs index 17beeee9ef1..6922b1c7cad 100644 --- a/integration-tests/src/tests/client/features/account_id_in_function_call_permission.rs +++ b/integration-tests/src/tests/client/features/account_id_in_function_call_permission.rs @@ -6,7 +6,7 @@ use near_parameters::RuntimeConfigStore; use near_primitives::account::{AccessKey, AccessKeyPermission, FunctionCallPermission}; use near_primitives::errors::{ActionsValidationError, InvalidTxError}; use near_primitives::hash::CryptoHash; -use near_primitives::transaction::{Action, AddKeyAction, Transaction}; +use near_primitives::transaction::{Action, AddKeyAction, Transaction, TransactionV0}; use nearcore::test_utils::TestEnvNightshadeSetupExt; #[test] @@ -36,7 +36,7 @@ fn test_account_id_in_function_call_permission_upgrade() { }; let signer = InMemorySigner::from_seed("test0".parse().unwrap(), KeyType::ED25519, "test0"); - let tx = Transaction { + let tx = TransactionV0 { signer_id: "test0".parse().unwrap(), receiver_id: "test0".parse().unwrap(), public_key: signer.public_key(), @@ -59,7 +59,7 @@ fn test_account_id_in_function_call_permission_upgrade() { { let tip = env.clients[0].chain.head().unwrap(); let signed_transaction = - Transaction { nonce: 10, block_hash: tip.last_block_hash, ..tx.clone() }.sign(&signer); + Transaction::V0(TransactionV0 { nonce: 10, block_hash: tip.last_block_hash, ..tx.clone() }).sign(&signer); assert_eq!( env.clients[0].process_tx(signed_transaction, false, false), ProcessTxResponse::ValidTx @@ -75,7 +75,7 @@ fn test_account_id_in_function_call_permission_upgrade() { { let tip = env.clients[0].chain.head().unwrap(); let signed_transaction = - Transaction { nonce: 11, block_hash: tip.last_block_hash, ..tx }.sign(&signer); + Transaction::V0(TransactionV0 { nonce: 11, block_hash: tip.last_block_hash, ..tx }).sign(&signer); assert_eq!( env.clients[0].process_tx(signed_transaction, false, false), ProcessTxResponse::InvalidTx(InvalidTxError::ActionsValidation( @@ -99,7 +99,7 @@ fn test_very_long_account_id() { let tip = env.clients[0].chain.head().unwrap(); let signer = InMemorySigner::from_seed("test0".parse().unwrap(), KeyType::ED25519, "test0"); - let tx = Transaction { + let tx = Transaction::V0(TransactionV0 { signer_id: "test0".parse().unwrap(), receiver_id: "test0".parse().unwrap(), public_key: signer.public_key(), @@ -116,7 +116,7 @@ fn test_very_long_account_id() { }))], nonce: 0, block_hash: tip.last_block_hash, - } + }) .sign(&signer); assert_eq!( diff --git a/integration-tests/src/tests/client/features/chunk_nodes_cache.rs b/integration-tests/src/tests/client/features/chunk_nodes_cache.rs index c94b46c2629..ffbefbf5338 100644 --- a/integration-tests/src/tests/client/features/chunk_nodes_cache.rs +++ b/integration-tests/src/tests/client/features/chunk_nodes_cache.rs @@ -51,6 +51,7 @@ fn process_transaction( })), ], last_block_hash, + 0 ); let tx_hash = tx.get_hash(); assert_eq!(env.clients[0].process_tx(tx, false, false), ProcessTxResponse::ValidTx); diff --git a/integration-tests/src/tests/client/features/flat_storage.rs b/integration-tests/src/tests/client/features/flat_storage.rs index d82d7c7befa..7a82285b737 100644 --- a/integration-tests/src/tests/client/features/flat_storage.rs +++ b/integration-tests/src/tests/client/features/flat_storage.rs @@ -5,7 +5,7 @@ use near_client::ProcessTxResponse; use near_crypto::{InMemorySigner, KeyType, Signer}; use near_parameters::ExtCosts; use near_primitives::test_utils::encode; -use near_primitives::transaction::{Action, ExecutionMetadata, FunctionCallAction, Transaction}; +use near_primitives::transaction::{Action, ExecutionMetadata, FunctionCallAction, Transaction, TransactionV0}; use near_primitives::version::ProtocolFeature; use near_primitives_core::hash::CryptoHash; use near_primitives_core::types::Gas; @@ -51,7 +51,7 @@ fn test_flat_storage_upgrade() { let signer = InMemorySigner::from_seed("test0".parse().unwrap(), KeyType::ED25519, "test0"); let gas = 20_000_000_000_000; - let tx = Transaction { + let tx = TransactionV0 { signer_id: "test0".parse().unwrap(), receiver_id: "test0".parse().unwrap(), public_key: signer.public_key(), @@ -69,12 +69,12 @@ fn test_flat_storage_upgrade() { deposit: 0, }))]; let tip = env.clients[0].chain.head().unwrap(); - let signed_transaction = Transaction { + let signed_transaction = Transaction::V0(TransactionV0 { nonce: 10, block_hash: tip.last_block_hash, actions: write_value_action, ..tx.clone() - } + }) .sign(&signer); let tx_hash = signed_transaction.get_hash(); assert_eq!( @@ -97,12 +97,12 @@ fn test_flat_storage_upgrade() { deposit: 0, }))]; let tip = env.clients[0].chain.head().unwrap(); - let signed_transaction = Transaction { + let signed_transaction = Transaction::V0(TransactionV0 { nonce: 20 + i, block_hash: tip.last_block_hash, actions: read_value_action, ..tx.clone() - } + }) .sign(&signer); let tx_hash = signed_transaction.get_hash(); assert_eq!( diff --git a/integration-tests/src/tests/client/features/increase_storage_compute_cost.rs b/integration-tests/src/tests/client/features/increase_storage_compute_cost.rs index af27e200217..33fc68b2aff 100644 --- a/integration-tests/src/tests/client/features/increase_storage_compute_cost.rs +++ b/integration-tests/src/tests/client/features/increase_storage_compute_cost.rs @@ -313,6 +313,7 @@ fn produce_saturated_chunk( &signer, actions.clone(), tip.last_block_hash, + 0 ); *nonce += 1; tx diff --git a/integration-tests/src/tests/client/features/lower_storage_key_limit.rs b/integration-tests/src/tests/client/features/lower_storage_key_limit.rs index 1897c415307..2c3a847dc2e 100644 --- a/integration-tests/src/tests/client/features/lower_storage_key_limit.rs +++ b/integration-tests/src/tests/client/features/lower_storage_key_limit.rs @@ -8,7 +8,7 @@ use near_o11y::testonly::init_test_logger; use near_parameters::RuntimeConfigStore; use near_primitives::errors::TxExecutionError; use near_primitives::hash::CryptoHash; -use near_primitives::transaction::{Action, FunctionCallAction, Transaction}; +use near_primitives::transaction::{Action, FunctionCallAction, Transaction, TransactionV0}; use near_primitives::types::BlockHeight; use near_primitives::views::FinalExecutionStatus; use nearcore::test_utils::TestEnvNightshadeSetupExt; @@ -61,7 +61,7 @@ fn protocol_upgrade() { }; let signer = InMemorySigner::from_seed("test0".parse().unwrap(), KeyType::ED25519, "test0"); - let tx = Transaction { + let tx = TransactionV0 { signer_id: "test0".parse().unwrap(), receiver_id: "test0".parse().unwrap(), public_key: signer.public_key(), @@ -80,7 +80,7 @@ fn protocol_upgrade() { { let tip = env.clients[0].chain.head().unwrap(); let signed_tx = - Transaction { nonce: tip.height + 1, block_hash: tip.last_block_hash, ..tx.clone() } + Transaction::V0(TransactionV0 { nonce: tip.height + 1, block_hash: tip.last_block_hash, ..tx.clone() }) .sign(&signer); let tx_hash = signed_tx.get_hash(); assert_eq!(env.clients[0].process_tx(signed_tx, false, false), ProcessTxResponse::ValidTx); @@ -100,7 +100,7 @@ fn protocol_upgrade() { { let tip = env.clients[0].chain.head().unwrap(); let signed_tx = - Transaction { nonce: tip.height + 1, block_hash: tip.last_block_hash, ..tx } + Transaction::V0(TransactionV0 { nonce: tip.height + 1, block_hash: tip.last_block_hash, ..tx }) .sign(&signer); let tx_hash = signed_tx.get_hash(); assert_eq!(env.clients[0].process_tx(signed_tx, false, false), ProcessTxResponse::ValidTx); @@ -121,7 +121,7 @@ fn protocol_upgrade() { .into_iter() .chain(near_primitives::test_utils::encode(&[20u64]).into_iter()) .collect(); - let tx = Transaction { + let tx = TransactionV0 { signer_id: "test0".parse().unwrap(), receiver_id: "test0".parse().unwrap(), public_key: signer.public_key(), @@ -137,7 +137,7 @@ fn protocol_upgrade() { }; let tip = env.clients[0].chain.head().unwrap(); let signed_tx = - Transaction { nonce: tip.height + 1, block_hash: tip.last_block_hash, ..tx } + Transaction::V0(TransactionV0 { nonce: tip.height + 1, block_hash: tip.last_block_hash, ..tx }) .sign(&signer); let tx_hash = signed_tx.get_hash(); assert_eq!(env.clients[0].process_tx(signed_tx, false, false), ProcessTxResponse::ValidTx); diff --git a/integration-tests/src/tests/client/features/nearvm.rs b/integration-tests/src/tests/client/features/nearvm.rs index 51332f66bcc..332f7684585 100644 --- a/integration-tests/src/tests/client/features/nearvm.rs +++ b/integration-tests/src/tests/client/features/nearvm.rs @@ -7,7 +7,7 @@ use near_client::ProcessTxResponse; use near_crypto::{InMemorySigner, KeyType, Signer}; use near_parameters::RuntimeConfigStore; use near_primitives::hash::CryptoHash; -use near_primitives::transaction::{Action, FunctionCallAction, Transaction}; +use near_primitives::transaction::{Action, FunctionCallAction, Transaction, TransactionV0}; use nearcore::test_utils::TestEnvNightshadeSetupExt; #[cfg_attr(all(target_arch = "aarch64", target_vendor = "apple"), ignore)] @@ -43,7 +43,7 @@ fn test_nearvm_upgrade() { }; let signer = InMemorySigner::from_seed("test0".parse().unwrap(), KeyType::ED25519, "test0"); - let tx = Transaction { + let tx = TransactionV0 { signer_id: "test0".parse().unwrap(), receiver_id: "test0".parse().unwrap(), public_key: signer.public_key(), @@ -62,7 +62,7 @@ fn test_nearvm_upgrade() { let logs_at_old_version = { let tip = env.clients[0].chain.head().unwrap(); let signed_transaction = - Transaction { nonce: 10, block_hash: tip.last_block_hash, ..tx.clone() }.sign(&signer); + Transaction::V0(TransactionV0 { nonce: 10, block_hash: tip.last_block_hash, ..tx.clone() }).sign(&signer); assert_eq!( env.clients[0].process_tx(signed_transaction, false, false), ProcessTxResponse::ValidTx @@ -79,7 +79,7 @@ fn test_nearvm_upgrade() { let logs_at_new_version = { let tip = env.clients[0].chain.head().unwrap(); let signed_transaction = - Transaction { nonce: 11, block_hash: tip.last_block_hash, ..tx }.sign(&signer); + Transaction::V0(TransactionV0 { nonce: 11, block_hash: tip.last_block_hash, ..tx }).sign(&signer); assert_eq!( env.clients[0].process_tx(signed_transaction, false, false), ProcessTxResponse::ValidTx diff --git a/integration-tests/src/tests/client/features/restore_receipts_after_fix_apply_chunks.rs b/integration-tests/src/tests/client/features/restore_receipts_after_fix_apply_chunks.rs index f3aa02df8ef..dd345e5a5db 100644 --- a/integration-tests/src/tests/client/features/restore_receipts_after_fix_apply_chunks.rs +++ b/integration-tests/src/tests/client/features/restore_receipts_after_fix_apply_chunks.rs @@ -41,7 +41,7 @@ fn run_test( .cloned() .unwrap_or_default() .iter() - .map(|receipt| receipt.receipt_id), + .map(|receipt| *receipt.receipt_id()), ) }; diff --git a/integration-tests/src/tests/client/features/storage_proof_size_limit.rs b/integration-tests/src/tests/client/features/storage_proof_size_limit.rs index eadaaf722d4..cf08dde996b 100644 --- a/integration-tests/src/tests/client/features/storage_proof_size_limit.rs +++ b/integration-tests/src/tests/client/features/storage_proof_size_limit.rs @@ -74,6 +74,7 @@ fn test_storage_proof_size_limit() { &signer, vec![action], env.clients[0].chain.head().unwrap().last_block_hash, + 0 ); nonce += 1; let res = env.execute_tx(tx).unwrap(); @@ -96,6 +97,7 @@ fn test_storage_proof_size_limit() { &signer, vec![action], after_writes_block_hash, + 0 ); nonce += 1; tx @@ -194,7 +196,7 @@ fn count_transfer_receipts(receipts: &[Receipt]) -> usize { } fn receipt_action(receipt: &Receipt) -> &Action { - match &receipt.receipt { + match receipt.receipt() { ReceiptEnum::Action(action_receipt) => &action_receipt.actions[0], _ => panic!("Expected Action receipt"), } diff --git a/integration-tests/src/tests/client/features/wallet_contract.rs b/integration-tests/src/tests/client/features/wallet_contract.rs index 2c3f8e68fab..72ff960c6c5 100644 --- a/integration-tests/src/tests/client/features/wallet_contract.rs +++ b/integration-tests/src/tests/client/features/wallet_contract.rs @@ -212,6 +212,7 @@ fn test_transaction_from_eth_implicit_account_fail() { access_key: AccessKey::full_access(), }))], *block.hash(), + 0 ); let response = env.clients[0].process_tx(add_access_key_to_eth_implicit_account_tx, false, false); @@ -226,6 +227,7 @@ fn test_transaction_from_eth_implicit_account_fail() { ð_implicit_account_signer, vec![Action::DeployContract(DeployContractAction { code: wallet_contract_code })], *block.hash(), + 0 ); let response = env.clients[0].process_tx(add_access_key_to_eth_implicit_account_tx, false, false); @@ -273,6 +275,7 @@ fn test_wallet_contract_interaction() { &relayer_signer.signer, actions, block_hash, + 0 ); height = check_tx_processing(&mut env, signed_transaction, height, blocks_number); @@ -395,6 +398,7 @@ fn create_rlp_execute_tx( &near_signer.signer, actions, block_hash, + 0 ) } diff --git a/integration-tests/src/tests/client/features/zero_balance_account.rs b/integration-tests/src/tests/client/features/zero_balance_account.rs index dd5ed8da9ca..0d265cc9ce1 100644 --- a/integration-tests/src/tests/client/features/zero_balance_account.rs +++ b/integration-tests/src/tests/client/features/zero_balance_account.rs @@ -192,6 +192,7 @@ fn test_zero_balance_account_add_key() { &new_signer, actions, *genesis_block.hash(), + 0 ); assert_eq!(env.clients[0].process_tx(add_key_tx, false, false), ProcessTxResponse::ValidTx); for i in 5..10 { @@ -222,6 +223,7 @@ fn test_zero_balance_account_add_key() { public_key: keys.last().unwrap().clone(), }))], *genesis_block.hash(), + 0 ); assert_eq!(env.clients[0].process_tx(delete_key_tx, false, false), ProcessTxResponse::ValidTx); for i in 10..15 { diff --git a/integration-tests/src/tests/client/process_blocks.rs b/integration-tests/src/tests/client/process_blocks.rs index f5bea12c712..608bf38f6ef 100644 --- a/integration-tests/src/tests/client/process_blocks.rs +++ b/integration-tests/src/tests/client/process_blocks.rs @@ -53,7 +53,7 @@ use near_primitives::test_utils::create_test_signer; use near_primitives::test_utils::TestBlockBuilder; use near_primitives::transaction::{ Action, DeployContractAction, ExecutionStatus, FunctionCallAction, SignedTransaction, - Transaction, + Transaction, TransactionV0, }; use near_primitives::trie_key::TrieKey; use near_primitives::types::validator_stake::ValidatorStake; @@ -163,6 +163,7 @@ pub(crate) fn deploy_test_contract_with_protocol_version( &signer, vec![Action::DeployContract(DeployContractAction { code: wasm_code.to_vec() })], *block.hash(), + 0 ); assert_eq!(env.clients[0].process_tx(tx, false, false), ProcessTxResponse::ValidTx); produce_blocks_from_height_with_protocol_version(env, epoch_length, height, protocol_version) @@ -214,6 +215,7 @@ pub(crate) fn prepare_env_with_congestion( code: near_test_contracts::backwards_compatible_rs_contract().to_vec(), })], *genesis_block.hash(), + 0 ); assert_eq!(env.clients[0].process_tx(tx, false, false), ProcessTxResponse::ValidTx); for i in 1..3 { @@ -248,6 +250,7 @@ pub(crate) fn prepare_env_with_congestion( deposit: 0, }))], *genesis_block.hash(), + 0 ); tx_hashes.push(signed_transaction.get_hash()); assert_eq!( @@ -1025,14 +1028,14 @@ fn test_process_invalid_tx() { let signer = InMemorySigner::from_seed("test1".parse().unwrap(), KeyType::ED25519, "test0"); let tx = SignedTransaction::new( Signature::empty(KeyType::ED25519), - Transaction { + Transaction::V0(TransactionV0 { signer_id: "test".parse().unwrap(), public_key: signer.public_key(), nonce: 0, receiver_id: "test".parse().unwrap(), block_hash: *env.clients[0].chain.genesis().hash(), actions: vec![], - }, + }), ); for i in 1..12 { env.produce_block(0, i); @@ -1043,14 +1046,14 @@ fn test_process_invalid_tx() { ); let tx2 = SignedTransaction::new( Signature::empty(KeyType::ED25519), - Transaction { + Transaction::V0(TransactionV0 { signer_id: "test".parse().unwrap(), public_key: signer.public_key(), nonce: 0, receiver_id: "test".parse().unwrap(), block_hash: hash(&[1]), actions: vec![], - }, + }), ); assert_eq!( env.clients[0].process_tx(tx2, false, false), @@ -2192,6 +2195,7 @@ fn test_validate_chunk_extra() { code: near_test_contracts::rs_contract().to_vec(), })], *genesis_block.hash(), + 0 ); assert_eq!(env.clients[0].process_tx(tx, false, false), ProcessTxResponse::ValidTx); let mut last_block = genesis_block; @@ -2214,6 +2218,7 @@ fn test_validate_chunk_extra() { deposit: 0, }))], *last_block.hash(), + 0 ); assert_eq!( env.clients[0].process_tx(function_call_tx, false, false), @@ -2615,6 +2620,7 @@ fn test_delayed_receipt_count_limit() { &signer, vec![Action::DeployContract(DeployContractAction { code: vec![92; 10000] })], *genesis_block.hash(), + 0 ); assert_eq!(env.clients[0].process_tx(tx, false, false), ProcessTxResponse::ValidTx); } @@ -3292,6 +3298,7 @@ fn test_validator_stake_host_function() { deposit: 0, }))], *genesis_block.hash(), + 0 ); assert_eq!( env.clients[0].process_tx(signed_transaction, false, false), diff --git a/integration-tests/src/tests/client/resharding.rs b/integration-tests/src/tests/client/resharding.rs index 06e45ae8517..a4b2b5f6cb2 100644 --- a/integration-tests/src/tests/client/resharding.rs +++ b/integration-tests/src/tests/client/resharding.rs @@ -551,7 +551,7 @@ impl TestReshardingEnv { for tx in txs_to_check { let id = &tx.get_hash(); - let signer_account_id = &tx.transaction.signer_id; + let signer_account_id = tx.transaction.signer_id(); let shard_uid = account_id_to_shard_uid(signer_account_id, &shard_layout); tracing::trace!(target: "test", tx=?id, ?signer_account_id, ?shard_uid, "checking tx"); @@ -633,10 +633,10 @@ impl TestReshardingEnv { .clone(); for receipt in outgoing_receipts.iter() { let target_shard_id = - client.chain.get_shard_id_for_receipt_id(&receipt.receipt_id).unwrap(); + client.chain.get_shard_id_for_receipt_id(receipt.receipt_id()).unwrap(); assert_eq!( target_shard_id, - account_id_to_shard_id(&receipt.receiver_id, &shard_layout) + account_id_to_shard_id(receipt.receiver_id(), &shard_layout) ); } } @@ -816,8 +816,7 @@ fn check_outgoing_receipts_reassigned_impl( // In V0->V1 resharding the outgoing receipts should be reassigned // to the receipt receiver's shard id. for receipt in outgoing_receipts { - let receiver = receipt.receiver_id; - let receiver_shard_id = account_id_to_shard_id(&receiver, &shard_layout); + let receiver_shard_id = account_id_to_shard_id(receipt.receiver_id(), &shard_layout); assert_eq!(receiver_shard_id, shard_id); } } @@ -1276,6 +1275,7 @@ fn setup_test_env_with_cross_contract_txs( &signer, actions, genesis_hash, + 0 ); init_txs.push(tx); } @@ -1449,6 +1449,7 @@ fn gen_cross_contract_tx_impl( deposit: 0, }))], *block_hash, + 0 ) } diff --git a/integration-tests/src/tests/nearcore/rpc_nodes.rs b/integration-tests/src/tests/nearcore/rpc_nodes.rs index 5f95324a68f..4a9063d055d 100644 --- a/integration-tests/src/tests/nearcore/rpc_nodes.rs +++ b/integration-tests/src/tests/nearcore/rpc_nodes.rs @@ -453,7 +453,7 @@ fn test_check_unknown_tx_must_return_error() { .EXPERIMENTAL_tx_status(RpcTransactionStatusRequest { transaction_info: TransactionInfo::TransactionId { tx_hash, - sender_account_id: transaction.transaction.signer_id, + sender_account_id: transaction.transaction.signer_id().clone(), }, wait_until: TxExecutionStatus::None, }) diff --git a/integration-tests/src/tests/runtime/deployment.rs b/integration-tests/src/tests/runtime/deployment.rs index 850e869c601..fa94b70ec1b 100644 --- a/integration-tests/src/tests/runtime/deployment.rs +++ b/integration-tests/src/tests/runtime/deployment.rs @@ -30,6 +30,7 @@ fn test_deploy_max_size_contract() { &*node_user.signer(), vec![Action::DeployContract(DeployContractAction { code: vec![0u8] })], block_hash, + 0 ); let tx_overhead = signed_transaction.get_size(); diff --git a/integration-tests/src/tests/standard_cases/mod.rs b/integration-tests/src/tests/standard_cases/mod.rs index a61a45bcac6..4f66a885e89 100644 --- a/integration-tests/src/tests/standard_cases/mod.rs +++ b/integration-tests/src/tests/standard_cases/mod.rs @@ -27,7 +27,7 @@ use std::sync::Arc; use crate::node::Node; use crate::user::User; use near_parameters::RuntimeConfig; -use near_primitives::receipt::{ActionReceipt, Receipt, ReceiptEnum}; +use near_primitives::receipt::{ActionReceipt, Receipt, ReceiptEnum, ReceiptV0}; use near_primitives::test_utils; use near_primitives::transaction::{Action, DeployContractAction, FunctionCallAction}; use testlib::fees_utils::FeeHelper; @@ -1441,12 +1441,12 @@ fn make_receipt(node: &impl Node, actions: Vec, receiver_id: AccountId) input_data_ids: vec![], actions, }); - Receipt { + Receipt::V0(ReceiptV0 { predecessor_id: alice_account(), receiver_id, receipt_id: CryptoHash::hash_borsh(&receipt_enum), receipt: receipt_enum, - } + }) } /// Check that numbers of charged trie node accesses during execution of the given receipts matches the provided @@ -1462,7 +1462,7 @@ fn check_trie_nodes_count( let node_user = node.user(); let mut node_touches: Vec<_> = vec![]; let receipt_hashes: Vec = - receipts.iter().map(|receipt| receipt.receipt_id).collect(); + receipts.iter().map(|receipt| *receipt.receipt_id()).collect(); for i in 0..2 { node_user.add_receipts(receipts.clone(), use_flat_storage).unwrap(); diff --git a/integration-tests/src/tests/test_errors.rs b/integration-tests/src/tests/test_errors.rs index 991ce7f2238..b1121975378 100644 --- a/integration-tests/src/tests/test_errors.rs +++ b/integration-tests/src/tests/test_errors.rs @@ -49,6 +49,7 @@ fn test_check_tx_error_log() { })), ], block_hash, + 0 ); let tx_result = node.user().commit_transaction(tx).unwrap_err(); @@ -89,6 +90,7 @@ fn test_deliver_tx_error_log() { })), ], block_hash, + 0 ); let tx_result = node.user().commit_transaction(tx).unwrap_err(); diff --git a/integration-tests/src/user/mod.rs b/integration-tests/src/user/mod.rs index 0799bf4570a..db8df92396d 100644 --- a/integration-tests/src/user/mod.rs +++ b/integration-tests/src/user/mod.rs @@ -106,6 +106,7 @@ pub trait User { &*self.signer(), actions, block_hash, + 0 ); self.commit_transaction(signed_transaction) } diff --git a/integration-tests/src/user/runtime_user.rs b/integration-tests/src/user/runtime_user.rs index c9d43a68ad3..f72490b5ba1 100644 --- a/integration-tests/src/user/runtime_user.rs +++ b/integration-tests/src/user/runtime_user.rs @@ -143,7 +143,7 @@ impl RuntimeUser { return Ok(()); } for receipt in apply_result.outgoing_receipts.iter() { - self.receipts.borrow_mut().insert(receipt.receipt_id, receipt.clone()); + self.receipts.borrow_mut().insert(*receipt.receipt_id(), receipt.clone()); } receipts = apply_result.outgoing_receipts; txs = vec![]; diff --git a/nearcore/src/metrics.rs b/nearcore/src/metrics.rs index 4eaab934c73..cf7b67c15b9 100644 --- a/nearcore/src/metrics.rs +++ b/nearcore/src/metrics.rs @@ -98,8 +98,8 @@ fn log_trie_item(key: Vec, value: Vec) { tracing::trace!( target: "metrics", "trie-stats - PostponedReceipt(predecessor_id: {:?}, receiver_id: {:?})", - receipt.predecessor_id, - receipt.receiver_id, + receipt.predecessor_id(), + receipt.receiver_id(), ); } _ => { diff --git a/runtime/runtime-params-estimator/src/action_costs.rs b/runtime/runtime-params-estimator/src/action_costs.rs index 8b0f2951a12..8184e9059a2 100644 --- a/runtime/runtime-params-estimator/src/action_costs.rs +++ b/runtime/runtime-params-estimator/src/action_costs.rs @@ -13,7 +13,7 @@ use crate::utils::{average_cost, percentiles}; use near_crypto::{KeyType, PublicKey}; use near_primitives::account::{AccessKey, AccessKeyPermission, FunctionCallPermission}; use near_primitives::hash::CryptoHash; -use near_primitives::receipt::{ActionReceipt, Receipt}; +use near_primitives::receipt::{ActionReceipt, Receipt, ReceiptV0}; use near_primitives::transaction::Action; use near_primitives::types::{AccountId, Gas}; use std::iter; @@ -264,12 +264,12 @@ impl ActionEstimation { input_data_ids: vec![], actions, }; - let receipt = Receipt { + let receipt = Receipt::V0(ReceiptV0 { predecessor_id, receiver_id, receipt_id: CryptoHash::new(), receipt: near_primitives::receipt::ReceiptEnum::Action(action_receipt), - }; + }); testbed.apply_action_receipt(&receipt, self.metric) } diff --git a/runtime/runtime-params-estimator/src/transaction_builder.rs b/runtime/runtime-params-estimator/src/transaction_builder.rs index d19040f3936..9617e934d11 100644 --- a/runtime/runtime-params-estimator/src/transaction_builder.rs +++ b/runtime/runtime-params-estimator/src/transaction_builder.rs @@ -62,6 +62,7 @@ impl TransactionBuilder { &signer, actions, CryptoHash::default(), + 0 ) } diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index 5f25f6af87c..198b4cfcc26 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -14,7 +14,7 @@ use near_primitives::checked_feature; use near_primitives::config::ViewConfig; use near_primitives::errors::{ActionError, ActionErrorKind, InvalidAccessKeyError, RuntimeError}; use near_primitives::hash::CryptoHash; -use near_primitives::receipt::{ActionReceipt, DataReceipt, Receipt, ReceiptEnum}; +use near_primitives::receipt::{ActionReceipt, DataReceipt, Receipt, ReceiptEnum, ReceiptPriority, ReceiptV0}; use near_primitives::transaction::{ Action, AddKeyAction, DeleteAccountAction, DeleteKeyAction, DeployContractAction, FunctionCallAction, StakeAction, @@ -254,7 +254,7 @@ pub(crate) fn action_function_call( apply_state, &mut runtime_ext, account, - &receipt.predecessor_id, + receipt.predecessor_id(), action_receipt, promise_results, function_call, @@ -349,7 +349,7 @@ pub(crate) fn action_function_call( actions: receipt.actions, }; - Receipt { + Receipt::V0(ReceiptV0 { predecessor_id: account_id.clone(), receiver_id: receipt.receiver_id, // Actual receipt ID is set in the Runtime.apply_action_receipt(...) in the @@ -360,7 +360,7 @@ pub(crate) fn action_function_call( } else { ReceiptEnum::Action(new_action_receipt) }, - } + }) }) .collect(); @@ -368,7 +368,7 @@ pub(crate) fn action_function_call( new_receipts.extend(receipt_manager.data_receipts.into_iter().map(|receipt| { let new_data_receipt = DataReceipt { data_id: receipt.data_id, data: receipt.data }; - Receipt { + Receipt::V0(ReceiptV0 { predecessor_id: account_id.clone(), receiver_id: account_id.clone(), // Actual receipt ID is set in the Runtime.apply_action_receipt(...) in the @@ -379,7 +379,7 @@ pub(crate) fn action_function_call( } else { ReceiptEnum::Data(new_data_receipt) }, - } + }) })); // Commit metadata for yielded promises queue @@ -712,12 +712,14 @@ pub(crate) fn action_delete_account( // We use current amount as a pay out to beneficiary. let account_balance = account.as_ref().unwrap().amount(); if account_balance > 0 { - result - .new_receipts - .push(Receipt::new_balance_refund(&delete_account.beneficiary_id, account_balance)); + result.new_receipts.push(Receipt::new_balance_refund( + &delete_account.beneficiary_id, + account_balance, + ReceiptPriority::NoPriority, + )); } remove_account(state_update, account_id)?; - *actor_id = receipt.predecessor_id.clone(); + *actor_id = receipt.predecessor_id().clone(); *account = None; Ok(()) } @@ -812,6 +814,7 @@ pub(crate) fn apply_delegate_action( sender_id: &AccountId, signed_delegate_action: &SignedDelegateAction, result: &mut ActionResult, + _priority: ReceiptPriority, ) -> Result<(), RuntimeError> { let delegate_action = &signed_delegate_action.delegate_action; @@ -840,7 +843,7 @@ pub(crate) fn apply_delegate_action( } // Generate a new receipt from DelegateAction. - let new_receipt = Receipt { + let new_receipt = Receipt::V0(ReceiptV0 { predecessor_id: sender_id.clone(), receiver_id: delegate_action.receiver_id.clone(), receipt_id: CryptoHash::default(), @@ -853,7 +856,7 @@ pub(crate) fn apply_delegate_action( input_data_ids: vec![], actions: delegate_action.get_actions(), }), - }; + }); // Note, Relayer prepaid all fees and all things required by actions: attached deposits and attached gas. // If something goes wrong, deposit is refunded to the predecessor, this is sender_id/Sender in DelegateAction. @@ -878,13 +881,13 @@ pub(crate) fn apply_delegate_action( /// Returns Gas amount is required to execute Receipt and all actions it contains fn receipt_required_gas(apply_state: &ApplyState, receipt: &Receipt) -> Result { - Ok(match &receipt.receipt { + Ok(match receipt.receipt() { ReceiptEnum::Action(action_receipt) | ReceiptEnum::PromiseYield(action_receipt) => { let mut required_gas = safe_add_gas( total_prepaid_exec_fees( &apply_state.config, &action_receipt.actions, - &receipt.receiver_id, + receipt.receiver_id(), )?, total_prepaid_gas(&action_receipt.actions)?, )?; @@ -1295,7 +1298,7 @@ mod tests { Some(Account::new(100, 0, 0, *code_hash, storage_usage, PROTOCOL_VERSION)); let mut actor_id = account_id.clone(); let mut action_result = ActionResult::default(); - let receipt = Receipt::new_balance_refund(&"alice.near".parse().unwrap(), 0); + let receipt = Receipt::new_balance_refund(&"alice.near".parse().unwrap(), 0, ReceiptPriority::NoPriority); let res = action_delete_account( state_update, &mut account, @@ -1466,13 +1469,14 @@ mod tests { &sender_id, &signed_delegate_action, &mut result, + ReceiptPriority::NoPriority ) .expect("Expect ok"); assert!(result.result.is_ok(), "Result error: {:?}", result.result.err()); assert_eq!( result.new_receipts, - vec![Receipt { + vec![Receipt::V0(ReceiptV0 { predecessor_id: sender_id.clone(), receiver_id: signed_delegate_action.delegate_action.receiver_id.clone(), receipt_id: CryptoHash::default(), @@ -1483,8 +1487,8 @@ mod tests { output_data_receivers: Vec::new(), input_data_ids: Vec::new(), actions: signed_delegate_action.delegate_action.get_actions(), - }) - }] + }), + })] ); } @@ -1510,6 +1514,7 @@ mod tests { &sender_id, &signed_delegate_action, &mut result, + ReceiptPriority::NoPriority ) .expect("Expect ok"); @@ -1536,6 +1541,7 @@ mod tests { &sender_id, &signed_delegate_action, &mut result, + ReceiptPriority::NoPriority ) .expect("Expect ok"); @@ -1562,6 +1568,7 @@ mod tests { &"www.test.near".parse().unwrap(), &signed_delegate_action, &mut result, + ReceiptPriority::NoPriority ) .expect("Expect ok"); diff --git a/runtime/runtime/src/balance_checker.rs b/runtime/runtime/src/balance_checker.rs index 27cfc8c7add..c81241e1e42 100644 --- a/runtime/runtime/src/balance_checker.rs +++ b/runtime/runtime/src/balance_checker.rs @@ -39,13 +39,13 @@ fn receipt_cost( config: &RuntimeConfig, receipt: &Receipt, ) -> Result { - Ok(match &receipt.receipt { + Ok(match receipt.receipt() { ReceiptEnum::Action(action_receipt) | ReceiptEnum::PromiseYield(action_receipt) => { let mut total_cost = total_deposit(&action_receipt.actions)?; - if !receipt.predecessor_id.is_system() { + if !receipt.predecessor_id().is_system() { let mut total_gas = safe_add_gas( config.fees.fee(ActionCosts::new_action_receipt).exec_fee(), - total_prepaid_exec_fees(config, &action_receipt.actions, &receipt.receiver_id)?, + total_prepaid_exec_fees(config, &action_receipt.actions, receipt.receiver_id())?, )?; total_gas = safe_add_gas(total_gas, total_prepaid_gas(&action_receipt.actions)?)?; total_gas = safe_add_gas( @@ -159,10 +159,10 @@ pub(crate) fn check_balance( // Accounts let mut all_accounts_ids: HashSet = transactions .iter() - .map(|tx| tx.transaction.signer_id.clone()) - .chain(incoming_receipts.iter().map(|r| r.receiver_id.clone())) - .chain(yield_timeout_receipts.iter().map(|r| r.receiver_id.clone())) - .chain(processed_delayed_receipts.iter().map(|r| r.receiver_id.clone())) + .map(|tx| tx.transaction.signer_id().clone()) + .chain(incoming_receipts.iter().map(|r| r.receiver_id().clone())) + .chain(yield_timeout_receipts.iter().map(|r| r.receiver_id().clone())) + .chain(processed_delayed_receipts.iter().map(|r| r.receiver_id().clone())) .collect(); let incoming_validator_rewards = if let Some(validator_accounts_update) = validator_accounts_update { @@ -202,10 +202,10 @@ pub(crate) fn check_balance( .chain(processed_delayed_receipts.iter()) .chain(yield_timeout_receipts.iter()) .filter_map(|receipt| { - let account_id = &receipt.receiver_id; - match &receipt.receipt { + let account_id = receipt.receiver_id(); + match receipt.receipt() { ReceiptEnum::Action(_) => { - Some(Ok((PostponedReceiptType::Action, account_id.clone(), receipt.receipt_id))) + Some(Ok((PostponedReceiptType::Action, account_id.clone(), *receipt.receipt_id()))) } ReceiptEnum::Data(data_receipt) => { let result = get( @@ -288,7 +288,7 @@ mod tests { use crate::ApplyStats; use near_crypto::{InMemorySigner, KeyType}; use near_primitives::hash::{hash, CryptoHash}; - use near_primitives::receipt::ActionReceipt; + use near_primitives::receipt::{ActionReceipt, ReceiptPriority, ReceiptV0}; use near_primitives::test_utils::account_new; use near_primitives::transaction::{Action, TransferAction}; use near_primitives::types::{MerkleHash, StateChangeCause}; @@ -332,7 +332,7 @@ mod tests { &RuntimeConfig::test(), &final_state, &None, - &[Receipt::new_balance_refund(&alice_account(), 1000)], + &[Receipt::new_balance_refund(&alice_account(), 1000, ReceiptPriority::NoPriority)], &[], &[], &[], @@ -392,7 +392,7 @@ mod tests { &RuntimeConfig::test(), &final_state, &None, - &[Receipt::new_balance_refund(&account_id, refund_balance)], + &[Receipt::new_balance_refund(&account_id, refund_balance, ReceiptPriority::NoPriority)], &[], &[], &[], @@ -443,19 +443,19 @@ mod tests { deposit, CryptoHash::default(), ); - let receipt = Receipt { - predecessor_id: tx.transaction.signer_id.clone(), - receiver_id: tx.transaction.receiver_id.clone(), + let receipt = Receipt::V0(ReceiptV0 { + predecessor_id: tx.transaction.signer_id().clone(), + receiver_id: tx.transaction.receiver_id().clone(), receipt_id: Default::default(), receipt: ReceiptEnum::Action(ActionReceipt { - signer_id: tx.transaction.signer_id.clone(), - signer_public_key: tx.transaction.public_key.clone(), + signer_id: tx.transaction.signer_id().clone(), + signer_public_key: tx.transaction.public_key().clone(), gas_price, output_data_receivers: vec![], input_data_ids: vec![], actions: vec![Action::Transfer(TransferAction { deposit })], }), - }; + }); check_balance( &cfg, @@ -502,19 +502,19 @@ mod tests { let tx = SignedTransaction::send_money(0, alice_id, bob_id, &signer, 2, CryptoHash::default()); - let receipt = Receipt { - predecessor_id: tx.transaction.signer_id.clone(), - receiver_id: tx.transaction.receiver_id.clone(), + let receipt = Receipt::V0(ReceiptV0 { + predecessor_id: tx.transaction.signer_id().clone(), + receiver_id: tx.transaction.receiver_id().clone(), receipt_id: Default::default(), receipt: ReceiptEnum::Action(ActionReceipt { - signer_id: tx.transaction.signer_id.clone(), - signer_public_key: tx.transaction.public_key.clone(), + signer_id: tx.transaction.signer_id().clone(), + signer_public_key: tx.transaction.public_key().clone(), gas_price, output_data_receivers: vec![], input_data_ids: vec![], actions: vec![Action::Transfer(TransferAction { deposit })], }), - }; + }); assert_eq!( check_balance( @@ -557,19 +557,19 @@ mod tests { let tx = SignedTransaction::send_money(0, alice_id, bob_id, &signer, 1, CryptoHash::default()); - let receipt = Receipt { - predecessor_id: tx.transaction.signer_id.clone(), - receiver_id: tx.transaction.receiver_id.clone(), + let receipt = Receipt::V0(ReceiptV0 { + predecessor_id: tx.transaction.signer_id().clone(), + receiver_id: tx.transaction.receiver_id().clone(), receipt_id: Default::default(), receipt: ReceiptEnum::Action(ActionReceipt { - signer_id: tx.transaction.signer_id.clone(), - signer_public_key: tx.transaction.public_key.clone(), + signer_id: tx.transaction.signer_id().clone(), + signer_public_key: tx.transaction.public_key().clone(), gas_price, output_data_receivers: vec![], input_data_ids: vec![], actions: vec![Action::Transfer(TransferAction { deposit })], }), - }; + }); // Alice's balance becomes u128::MAX, which causes it is interpreted as // the Alice's account version to be 2 or higher, instead of being interpreted diff --git a/runtime/runtime/src/config.rs b/runtime/runtime/src/config.rs index c5681c8481f..80c8a735588 100644 --- a/runtime/runtime/src/config.rs +++ b/runtime/runtime/src/config.rs @@ -259,17 +259,18 @@ pub fn tx_cost( total_send_fees( config, sender_is_receiver, - &transaction.actions, - &transaction.receiver_id, + transaction.actions(), + transaction.receiver_id(), )?, )?; let prepaid_gas = safe_add_gas( - total_prepaid_gas(&transaction.actions)?, - total_prepaid_send_fees(config, &transaction.actions)?, + total_prepaid_gas(&transaction.actions())?, + total_prepaid_send_fees(config, &transaction.actions())?, )?; // If signer is equals to receiver the receipt will be processed at the same block as this // transaction. Otherwise it will processed in the next block and the gas might be inflated. - let initial_receipt_hop = if transaction.signer_id == transaction.receiver_id { 0 } else { 1 }; + let initial_receipt_hop = + if transaction.signer_id() == transaction.receiver_id() { 0 } else { 1 }; let minimum_new_receipt_gas = if protocol_version < FIXED_MINIMUM_NEW_RECEIPT_GAS_VERSION { fees.min_receipt_with_function_call_gas() } else { @@ -298,13 +299,19 @@ pub fn tx_cost( safe_add_gas(prepaid_gas, fees.fee(ActionCosts::new_action_receipt).exec_fee())?; gas_remaining = safe_add_gas( gas_remaining, - total_prepaid_exec_fees(config, &transaction.actions, &transaction.receiver_id)?, + total_prepaid_exec_fees(config, transaction.actions(), transaction.receiver_id())?, )?; let burnt_amount = safe_gas_to_balance(gas_price, gas_burnt)?; let remaining_gas_amount = safe_gas_to_balance(receipt_gas_price, gas_remaining)?; let mut total_cost = safe_add_balance(burnt_amount, remaining_gas_amount)?; - total_cost = safe_add_balance(total_cost, total_deposit(&transaction.actions)?)?; - Ok(TransactionCost { gas_burnt, gas_remaining, receipt_gas_price, total_cost, burnt_amount }) + total_cost = safe_add_balance(total_cost, total_deposit(&transaction.actions())?)?; + Ok(TransactionCost { + gas_burnt, + gas_remaining, + receipt_gas_price, + total_cost, + burnt_amount, + }) } /// Total sum of gas that would need to be burnt before we start executing the given actions. diff --git a/runtime/runtime/src/lib.rs b/runtime/runtime/src/lib.rs index 32669afc8c2..877fe74c036 100644 --- a/runtime/runtime/src/lib.rs +++ b/runtime/runtime/src/lib.rs @@ -20,8 +20,7 @@ use near_primitives::errors::{ }; use near_primitives::hash::CryptoHash; use near_primitives::receipt::{ - ActionReceipt, DataReceipt, DelayedReceiptIndices, PromiseYieldIndices, PromiseYieldTimeout, - Receipt, ReceiptEnum, ReceivedData, + ActionReceipt, DataReceipt, DelayedReceiptIndices, PromiseYieldIndices, PromiseYieldTimeout, Receipt, ReceiptEnum, ReceiptV0, ReceivedData }; use near_primitives::runtime::migration_data::{MigrationData, MigrationFlags}; use near_primitives::sandbox::state_patch::SandboxStatePatch; @@ -292,19 +291,19 @@ impl Runtime { &apply_state.prev_block_hash, &apply_state.block_hash, ); - let receipt = Receipt { - predecessor_id: transaction.signer_id.clone(), - receiver_id: transaction.receiver_id.clone(), + let receipt = Receipt::V0(ReceiptV0 { + predecessor_id: transaction.signer_id().clone(), + receiver_id: transaction.receiver_id().clone(), receipt_id, receipt: ReceiptEnum::Action(ActionReceipt { - signer_id: transaction.signer_id.clone(), - signer_public_key: transaction.public_key.clone(), + signer_id: transaction.signer_id().clone(), + signer_public_key: transaction.public_key().clone(), gas_price: verification_result.receipt_gas_price, output_data_receivers: vec![], input_data_ids: vec![], - actions: transaction.actions.clone(), + actions: transaction.actions().to_vec(), }), - }; + }); stats.tx_burnt_amount = safe_add_balance(stats.tx_burnt_amount, verification_result.burnt_amount)?; let gas_burnt = verification_result.gas_burnt; @@ -312,14 +311,14 @@ impl Runtime { let outcome = ExecutionOutcomeWithId { id: signed_transaction.get_hash(), outcome: ExecutionOutcome { - status: ExecutionStatus::SuccessReceiptId(receipt.receipt_id), + status: ExecutionStatus::SuccessReceiptId(*receipt.receipt_id()), logs: vec![], - receipt_ids: vec![receipt.receipt_id], + receipt_ids: vec![*receipt.receipt_id()], gas_burnt, // TODO(#8806): Support compute costs for actions. For now they match burnt gas. compute_usage: Some(compute_usage), tokens_burnt: verification_result.burnt_amount, - executor_id: transaction.signer_id.clone(), + executor_id: transaction.signer_id().clone(), // TODO: profile data is only counted in apply_action, which only happened at process_receipt // VerificationResult needs updates to incorporate profile data to support profile data of txns metadata: ExecutionMetadata::V1, @@ -352,14 +351,14 @@ impl Runtime { actions: &[Action], epoch_info_provider: &dyn EpochInfoProvider, ) -> Result { - let exec_fees = exec_fee(&apply_state.config, action, &receipt.receiver_id); + let exec_fees = exec_fee(&apply_state.config, action, receipt.receiver_id()); let mut result = ActionResult::default(); result.gas_used = exec_fees; result.gas_burnt = exec_fees; // TODO(#8806): Support compute costs for actions. For now they match burnt gas. result.compute_usage = exec_fees; - let account_id = &receipt.receiver_id; - let is_refund = receipt.predecessor_id.is_system(); + let account_id = receipt.receiver_id(); + let is_refund = receipt.predecessor_id().is_system(); let is_the_only_action = actions.len() == 1; let implicit_account_creation_eligible = is_the_only_action && !is_refund; @@ -390,8 +389,8 @@ impl Runtime { &apply_state.config.account_creation_config, account, actor_id, - &receipt.receiver_id, - &receipt.predecessor_id, + receipt.receiver_id(), + receipt.predecessor_id(), &mut result, apply_state.current_protocol_version, ); @@ -504,6 +503,7 @@ impl Runtime { account_id, signed_delegate_action, &mut result, + receipt.priority() )?; } }; @@ -521,13 +521,13 @@ impl Runtime { stats: &mut ApplyStats, epoch_info_provider: &dyn EpochInfoProvider, ) -> Result { - let action_receipt = match &receipt.receipt { + let action_receipt = match receipt.receipt() { ReceiptEnum::Action(action_receipt) | ReceiptEnum::PromiseYield(action_receipt) => { action_receipt } _ => unreachable!("given receipt should be an action receipt"), }; - let account_id = &receipt.receiver_id; + let account_id = receipt.receiver_id(); // Collecting input data and removing it from the state let promise_results = action_receipt .input_data_ids @@ -557,7 +557,7 @@ impl Runtime { }); let mut account = get_account(state_update, account_id)?; - let mut actor_id = receipt.predecessor_id.clone(); + let mut actor_id = receipt.predecessor_id().clone(); let mut result = ActionResult::default(); let exec_fees = apply_state.config.fees.fee(ActionCosts::new_action_receipt).exec_fee(); result.gas_used = exec_fees; @@ -571,7 +571,7 @@ impl Runtime { for (action_index, action) in action_receipt.actions.iter().enumerate() { let action_hash = create_action_hash_from_receipt_id( apply_state.current_protocol_version, - &receipt.receipt_id, + receipt.receipt_id(), &apply_state.prev_block_hash, &apply_state.block_hash, action_index, @@ -649,7 +649,7 @@ impl Runtime { } } - let gas_deficit_amount = if receipt.predecessor_id.is_system() { + let gas_deficit_amount = if receipt.predecessor_id().is_system() { // We will set gas_burnt for refund receipts to be 0 when we calculate tx_burnt_amount // Here we don't set result.gas_burnt to be zero if CountRefundReceiptsInGasLimit is // enabled because we want it to be counted in gas limit calculation later @@ -705,7 +705,7 @@ impl Runtime { } // If the receipt is a refund, then we consider it free without burnt gas. - let gas_burnt: Gas = if receipt.predecessor_id.is_system() { 0 } else { result.gas_burnt }; + let gas_burnt: Gas = if receipt.predecessor_id().is_system() { 0 } else { result.gas_burnt }; // `gas_deficit_amount` is strictly less than `gas_price * gas_burnt`. let mut tx_burnt_amount = safe_gas_to_balance(apply_state.gas_price, gas_burnt)? - gas_deficit_amount; @@ -751,7 +751,7 @@ impl Runtime { .new_receipts .get_mut(receipt_index as usize) .expect("the receipt for the given receipt index should exist") - .receipt + .receipt_mut() { ReceiptEnum::Action(ref mut new_action_receipt) | ReceiptEnum::PromiseYield(ref mut new_action_receipt) => new_action_receipt @@ -766,7 +766,7 @@ impl Runtime { Err(_) => None, }; result.new_receipts.extend(action_receipt.output_data_receivers.iter().map( - |data_receiver| Receipt { + |data_receiver| Receipt::V0(ReceiptV0 { predecessor_id: account_id.clone(), receiver_id: data_receiver.receiver_id.clone(), receipt_id: CryptoHash::default(), @@ -774,7 +774,7 @@ impl Runtime { data_id: data_receiver.data_id, data: data.clone(), }), - }, + }), )); }; } @@ -787,15 +787,15 @@ impl Runtime { .filter_map(|(receipt_index, mut new_receipt)| { let receipt_id = create_receipt_id_from_receipt_id( apply_state.current_protocol_version, - &receipt.receipt_id, + receipt.receipt_id(), &apply_state.prev_block_hash, &apply_state.block_hash, receipt_index, ); - new_receipt.receipt_id = receipt_id; + new_receipt.set_receipt_id(receipt_id); let is_action = matches!( - &new_receipt.receipt, + new_receipt.receipt(), ReceiptEnum::Action(_) | ReceiptEnum::PromiseYield(_) ); outgoing_receipts.push(new_receipt); @@ -811,7 +811,7 @@ impl Runtime { Ok(ReturnData::ReceiptIndex(receipt_index)) => { ExecutionStatus::SuccessReceiptId(create_receipt_id_from_receipt_id( apply_state.current_protocol_version, - &receipt.receipt_id, + receipt.receipt_id(), &apply_state.prev_block_hash, &apply_state.block_hash, receipt_index as usize, @@ -825,7 +825,7 @@ impl Runtime { Self::print_log(&result.logs); Ok(ExecutionOutcomeWithId { - id: receipt.receipt_id, + id: *receipt.receipt_id(), outcome: ExecutionOutcome { status, logs: result.logs, @@ -853,7 +853,7 @@ impl Runtime { total_prepaid_send_fees(config, &action_receipt.actions)?, )?; let prepaid_exec_gas = safe_add_gas( - total_prepaid_exec_fees(config, &action_receipt.actions, &receipt.receiver_id)?, + total_prepaid_exec_fees(config, &action_receipt.actions, receipt.receiver_id())?, config.fees.fee(ActionCosts::new_action_receipt).exec_fee(), )?; let deposit_refund = if result.result.is_err() { total_deposit } else { 0 }; @@ -893,9 +893,11 @@ impl Runtime { } if deposit_refund > 0 { - result - .new_receipts - .push(Receipt::new_balance_refund(&receipt.predecessor_id, deposit_refund)); + result.new_receipts.push(Receipt::new_balance_refund( + receipt.predecessor_id(), + deposit_refund, + receipt.priority(), + )); } if gas_balance_refund > 0 { // Gas refunds refund the allowance of the access key, so if the key exists on the @@ -904,6 +906,7 @@ impl Runtime { &action_receipt.signer_id, gas_balance_refund, action_receipt.signer_public_key.clone(), + receipt.priority(), )); } Ok(gas_deficit_amount) @@ -919,8 +922,8 @@ impl Runtime { stats: &mut ApplyStats, epoch_info_provider: &dyn EpochInfoProvider, ) -> Result, RuntimeError> { - let account_id = &receipt.receiver_id; - match receipt.receipt { + let account_id = receipt.receiver_id(); + match receipt.receipt() { ReceiptEnum::Data(ref data_receipt) => { // Received a new data receipt. // Saving the data into the state keyed by the data_id. @@ -1024,7 +1027,7 @@ impl Runtime { receiver_id: account_id.clone(), data_id: *data_id, }, - &receipt.receipt_id, + receipt.receipt_id(), ) } } @@ -1049,7 +1052,7 @@ impl Runtime { state_update, TrieKey::PendingDataCount { receiver_id: account_id.clone(), - receipt_id: receipt.receipt_id, + receipt_id: *receipt.receipt_id(), }, &pending_data_count, ); @@ -1389,7 +1392,7 @@ impl Runtime { signed_transaction, &mut stats, )?; - if receipt.receiver_id == signed_transaction.transaction.signer_id { + if receipt.receiver_id() == signed_transaction.transaction.signer_id() { local_receipts.push(receipt); } else { outgoing_receipts.push(receipt); @@ -1417,10 +1420,10 @@ impl Runtime { let span = tracing::debug_span!( target: "runtime", "process_receipt", - receipt_id = %receipt.receipt_id, - predecessor = %receipt.predecessor_id, - receiver = %receipt.receiver_id, - id = %receipt.receipt_id, + receipt_id = %receipt.receipt_id(), + predecessor = %receipt.predecessor_id(), + receiver = %receipt.receiver_id(), + id = %receipt.receipt_id(), gas_burnt = tracing::field::Empty, compute_usage = tracing::field::Empty, ) @@ -1648,7 +1651,7 @@ impl Runtime { new_receipt_index += 1; // Create a PromiseResume receipt to resolve the timed-out yield. - let resume_receipt = Receipt { + let resume_receipt = Receipt::V0(ReceiptV0 { predecessor_id: queue_entry.account_id.clone(), receiver_id: queue_entry.account_id.clone(), receipt_id: new_receipt_id, @@ -1656,7 +1659,7 @@ impl Runtime { data_id: queue_entry.data_id, data: None, }), - }; + }); // For yielded promises the sender is always the receiver. We can process // the receipt directly because we know it is destined for the local shard. @@ -1808,10 +1811,10 @@ fn action_transfer_or_implicit_account_creation( action_transfer(account, deposit)?; } // Check if this is a gas refund, then try to refund the access key allowance. - if is_refund && action_receipt.signer_id == receipt.receiver_id { + if is_refund && &action_receipt.signer_id == receipt.receiver_id() { try_refund_allowance( state_update, - &receipt.receiver_id, + receipt.receiver_id(), &action_receipt.signer_public_key, deposit, )?; @@ -1826,7 +1829,7 @@ fn action_transfer_or_implicit_account_creation( &apply_state.config.fees, account, actor_id, - &receipt.receiver_id, + receipt.receiver_id(), deposit, apply_state.block_height, apply_state.current_protocol_version, @@ -1864,6 +1867,7 @@ mod tests { use near_parameters::{ExtCosts, ParameterCost, RuntimeConfig}; use near_primitives::account::AccessKey; use near_primitives::hash::hash; + use near_primitives::receipt::ReceiptPriority; use near_primitives::shard_layout::ShardUId; use near_primitives::test_utils::{account_new, MockEpochInfoProvider}; use near_primitives::transaction::{ @@ -1889,7 +1893,7 @@ mod tests { signer: Arc, actions: Vec, ) -> Receipt { - Receipt { + Receipt::V0(ReceiptV0 { predecessor_id: account_id.clone(), receiver_id: account_id.clone(), receipt_id: CryptoHash::hash_borsh(actions.clone()), @@ -1901,7 +1905,7 @@ mod tests { input_data_ids: vec![], actions, }), - } + }) } #[test] @@ -2031,7 +2035,7 @@ mod tests { tries.get_trie_for_shard(ShardUId::single_shard(), root), &Some(validator_accounts_update), &apply_state, - &[Receipt::new_balance_refund(&alice_account(), small_refund)], + &[Receipt::new_balance_refund(&alice_account(), small_refund, ReceiptPriority::NoPriority)], &[], &epoch_info_provider, Default::default(), @@ -2254,7 +2258,7 @@ mod tests { (0..n) .map(|i| { receipt_id = hash(receipt_id.as_ref()); - Receipt { + Receipt::V0(ReceiptV0 { predecessor_id: bob_account(), receiver_id: alice_account(), receipt_id, @@ -2268,7 +2272,7 @@ mod tests { deposit: small_transfer + Balance::from(i), })], }), - } + }) }) .collect() } @@ -2278,7 +2282,7 @@ mod tests { (0..n) .map(|i| { receipt_id = hash(receipt_id.as_ref()); - Receipt::new_balance_refund(&alice_account(), small_transfer + Balance::from(i)) + Receipt::new_balance_refund(&alice_account(), small_transfer + Balance::from(i), ReceiptPriority::NoPriority) }) .collect() } @@ -2407,7 +2411,7 @@ mod tests { &apply_state.prev_block_hash, &apply_state.block_hash, ), // receipt for tx 3 - receipts[0].receipt_id, // receipt #0 + *receipts[0].receipt_id(), // receipt #0 ], "STEP #2 failed", ); @@ -2490,8 +2494,8 @@ mod tests { assert_eq!( apply_result.outcomes.iter().map(|o| o.id).collect::>(), vec![ - receipts[1].receipt_id, // receipt #1 - receipts[2].receipt_id, // receipt #2 + *receipts[1].receipt_id(), // receipt #1 + *receipts[2].receipt_id(), // receipt #2 create_receipt_id_from_transaction( PROTOCOL_VERSION, &local_transactions[8], @@ -2520,9 +2524,9 @@ mod tests { assert_eq!( apply_result.outcomes.iter().map(|o| o.id).collect::>(), vec![ - receipts[3].receipt_id, // receipt #3 - receipts[4].receipt_id, // receipt #4 - receipts[5].receipt_id, // receipt #5 + *receipts[3].receipt_id(), // receipt #3 + *receipts[4].receipt_id(), // receipt #4 + *receipts[5].receipt_id(), // receipt #5 ], "STEP #5 failed", ); @@ -2539,7 +2543,7 @@ mod tests { let n = 1; let mut receipts = generate_receipts(small_transfer, n); - if let ReceiptEnum::Action(action_receipt) = &mut receipts.get_mut(0).unwrap().receipt { + if let ReceiptEnum::Action(action_receipt) = receipts.get_mut(0).unwrap().receipt_mut() { action_receipt.gas_price = GAS_PRICE / 10; } @@ -2579,7 +2583,7 @@ mod tests { total_prepaid_exec_fees(&apply_state.config, &actions, &alice_account()).unwrap(), ) .unwrap(); - let receipts = vec![Receipt { + let receipts = vec![Receipt::V0(ReceiptV0 { predecessor_id: bob_account(), receiver_id: alice_account(), receipt_id: CryptoHash::default(), @@ -2591,7 +2595,7 @@ mod tests { input_data_ids: vec![], actions, }), - }]; + })]; let total_receipt_cost = Balance::from(gas + expected_gas_burnt) * gas_price; let expected_gas_burnt_amount = Balance::from(expected_gas_burnt) * GAS_PRICE; let expected_refund = total_receipt_cost - expected_gas_burnt_amount; @@ -2610,7 +2614,7 @@ mod tests { // We used part of the prepaid gas to paying extra fees. assert_eq!(result.stats.gas_deficit_amount, 0); // The refund is less than the received amount. - match &result.outgoing_receipts[0].receipt { + match result.outgoing_receipts[0].receipt() { ReceiptEnum::Action(ActionReceipt { actions, .. }) => { assert!( matches!(actions[0], Action::Transfer(TransferAction { deposit }) if deposit == expected_refund) @@ -2642,7 +2646,7 @@ mod tests { total_prepaid_exec_fees(&apply_state.config, &actions, &alice_account()).unwrap(), ) .unwrap(); - let receipts = vec![Receipt { + let receipts = vec![Receipt::V0(ReceiptV0 { predecessor_id: bob_account(), receiver_id: alice_account(), receipt_id: CryptoHash::default(), @@ -2654,7 +2658,7 @@ mod tests { input_data_ids: vec![], actions, }), - }]; + })]; let total_receipt_cost = Balance::from(gas + expected_gas_burnt) * gas_price; let expected_gas_burnt_amount = Balance::from(expected_gas_burnt) * GAS_PRICE; let expected_deficit = expected_gas_burnt_amount - total_receipt_cost; @@ -2881,10 +2885,10 @@ mod tests { // Only first two receipts should fit into the chunk due to the compute usage limit. assert_matches!(&apply_result.outcomes[..], [first, second] => { - assert_eq!(first.id, deploy_contract_receipt.receipt_id); + assert_eq!(first.id, *deploy_contract_receipt.receipt_id()); assert_matches!(first.outcome.status, ExecutionStatus::SuccessValue(_)); - assert_eq!(second.id, first_call_receipt.receipt_id); + assert_eq!(second.id, *first_call_receipt.receipt_id()); assert_eq!(second.outcome.compute_usage.unwrap(), sha256_cost.compute); assert_matches!(second.outcome.status, ExecutionStatus::SuccessValue(_)); }); @@ -2902,7 +2906,7 @@ mod tests { .unwrap(); assert_matches!(&apply_result.outcomes[..], [ExecutionOutcomeWithId { id, outcome }] => { - assert_eq!(*id, second_call_receipt.receipt_id); + assert_eq!(id, second_call_receipt.receipt_id()); assert_eq!(outcome.compute_usage.unwrap(), sha256_cost.compute); assert_matches!(outcome.status, ExecutionStatus::SuccessValue(_)); }); @@ -2945,10 +2949,10 @@ mod tests { .unwrap(); assert_matches!(&apply_result.outcomes[..], [first, second] => { - assert_eq!(first.id, deploy_contract_receipt.receipt_id); + assert_eq!(first.id, *deploy_contract_receipt.receipt_id()); assert_matches!(first.outcome.status, ExecutionStatus::SuccessValue(_)); - assert_eq!(second.id, first_call_receipt.receipt_id); + assert_eq!(second.id, *first_call_receipt.receipt_id()); assert_matches!(second.outcome.status, ExecutionStatus::Failure(_)); }); } diff --git a/runtime/runtime/src/prefetch.rs b/runtime/runtime/src/prefetch.rs index 2f7fe53fa6b..88b268bf501 100644 --- a/runtime/runtime/src/prefetch.rs +++ b/runtime/runtime/src/prefetch.rs @@ -92,8 +92,8 @@ impl TriePrefetcher { receipts: &[Receipt], ) -> Result<(), PrefetchError> { for receipt in receipts.iter() { - let is_refund = receipt.predecessor_id.is_system(); - let action_receipt = match &receipt.receipt { + let is_refund = receipt.predecessor_id().is_system(); + let action_receipt = match receipt.receipt() { ReceiptEnum::Action(action_receipt) | ReceiptEnum::PromiseYield(action_receipt) => { action_receipt } @@ -101,7 +101,7 @@ impl TriePrefetcher { continue; } }; - let account_id = receipt.receiver_id.clone(); + let account_id = receipt.receiver_id().clone(); // general-purpose account prefetching if self.prefetch_api.enable_receipt_prefetching { @@ -147,7 +147,7 @@ impl TriePrefetcher { continue; }; if self.prefetch_api.sweat_prefetch_receivers.contains(&account_id) - && self.prefetch_api.sweat_prefetch_senders.contains(&receipt.predecessor_id) + && self.prefetch_api.sweat_prefetch_senders.contains(receipt.predecessor_id()) { if fn_call.method_name == "record_batch" { self.prefetch_sweat_record_batch(account_id.clone(), &fn_call.args)?; @@ -159,7 +159,7 @@ impl TriePrefetcher { let config = claim_sweat_cfg.iter().find(|cfg| { cfg.receiver == account_id.as_str() && cfg.method_name == fn_call.method_name - && cfg.sender == receipt.predecessor_id.as_str() + && cfg.sender == receipt.predecessor_id().as_str() }); if config.is_some() { self.prefetch_claim_sweat_record_batch_for_hold( @@ -176,13 +176,13 @@ impl TriePrefetcher { if config.is_some() { self.prefetch_claim_sweat_claim( account_id.clone(), - receipt.predecessor_id.clone(), + receipt.predecessor_id().clone(), )? } } if self.prefetch_api.kaiching_prefetch_config.iter().any(|cfg| { - cfg.sender == receipt.predecessor_id.as_str() + cfg.sender == receipt.predecessor_id().as_str() && cfg.receiver == account_id.as_str() && cfg.method_name == fn_call.method_name }) { @@ -204,13 +204,13 @@ impl TriePrefetcher { ) -> Result<(), PrefetchError> { if self.prefetch_api.enable_receipt_prefetching { for t in transactions { - let account_id = t.transaction.signer_id.clone(); + let account_id = t.transaction.signer_id().clone(); let trie_key = TrieKey::Account { account_id }; self.prefetch_trie_key(trie_key)?; let trie_key = TrieKey::AccessKey { - account_id: t.transaction.signer_id.clone(), - public_key: t.transaction.public_key.clone(), + account_id: t.transaction.signer_id().clone(), + public_key: t.transaction.public_key().clone(), }; self.prefetch_trie_key(trie_key)?; } diff --git a/runtime/runtime/src/verifier.rs b/runtime/runtime/src/verifier.rs index 2c4647e80e3..46594af3f22 100644 --- a/runtime/runtime/src/verifier.rs +++ b/runtime/runtime/src/verifier.rs @@ -99,12 +99,12 @@ pub fn validate_transaction( current_protocol_version: ProtocolVersion, ) -> Result { let transaction = &signed_transaction.transaction; - let signer_id = &transaction.signer_id; + let signer_id = transaction.signer_id(); if verify_signature && !signed_transaction .signature - .verify(signed_transaction.get_hash().as_ref(), &transaction.public_key) + .verify(signed_transaction.get_hash().as_ref(), transaction.public_key()) { return Err(InvalidTxError::InvalidSignature.into()); } @@ -121,12 +121,12 @@ pub fn validate_transaction( validate_actions( &config.wasm_config.limit_config, - &transaction.actions, + transaction.actions(), current_protocol_version, ) .map_err(InvalidTxError::ActionsValidation)?; - let sender_is_receiver = &transaction.receiver_id == signer_id; + let sender_is_receiver = transaction.receiver_id() == signer_id; tx_cost(&config, transaction, gas_price, sender_is_receiver, current_protocol_version) .map_err(|_| InvalidTxError::CostOverflow.into()) @@ -143,7 +143,7 @@ pub fn verify_and_charge_transaction( block_height: Option, current_protocol_version: ProtocolVersion, ) -> Result { - let TransactionCost { gas_burnt, gas_remaining, receipt_gas_price, total_cost, burnt_amount } = + let TransactionCost { gas_burnt, gas_remaining, receipt_gas_price, total_cost, burnt_amount, } = validate_transaction( config, gas_price, @@ -151,8 +151,9 @@ pub fn verify_and_charge_transaction( verify_signature, current_protocol_version, )?; + let transaction = &signed_transaction.transaction; - let signer_id = &transaction.signer_id; + let signer_id = transaction.signer_id(); let mut signer = match get_account(state_update, signer_id)? { Some(signer) => signer, @@ -160,22 +161,22 @@ pub fn verify_and_charge_transaction( return Err(InvalidTxError::SignerDoesNotExist { signer_id: signer_id.clone() }.into()); } }; - let mut access_key = match get_access_key(state_update, signer_id, &transaction.public_key)? { + let mut access_key = match get_access_key(state_update, signer_id, transaction.public_key())? { Some(access_key) => access_key, None => { return Err(InvalidTxError::InvalidAccessKeyError( InvalidAccessKeyError::AccessKeyNotFound { account_id: signer_id.clone(), - public_key: transaction.public_key.clone().into(), + public_key: transaction.public_key().clone().into(), }, ) .into()); } }; - if transaction.nonce <= access_key.nonce { + if transaction.nonce() <= access_key.nonce { return Err(InvalidTxError::InvalidNonce { - tx_nonce: transaction.nonce, + tx_nonce: transaction.nonce(), ak_nonce: access_key.nonce, } .into()); @@ -184,9 +185,9 @@ pub fn verify_and_charge_transaction( if let Some(height) = block_height { let upper_bound = height * near_primitives::account::AccessKey::ACCESS_KEY_NONCE_RANGE_MULTIPLIER; - if transaction.nonce >= upper_bound { + if transaction.nonce() >= upper_bound { return Err(InvalidTxError::NonceTooLarge { - tx_nonce: transaction.nonce, + tx_nonce: transaction.nonce(), upper_bound, } .into()); @@ -194,7 +195,7 @@ pub fn verify_and_charge_transaction( } }; - access_key.nonce = transaction.nonce; + access_key.nonce = transaction.nonce(); signer.set_amount(signer.amount().checked_sub(total_cost).ok_or_else(|| { InvalidTxError::NotEnoughBalance { @@ -211,7 +212,7 @@ pub fn verify_and_charge_transaction( *allowance = allowance.checked_sub(total_cost).ok_or_else(|| { InvalidTxError::InvalidAccessKeyError(InvalidAccessKeyError::NotEnoughAllowance { account_id: signer_id.clone(), - public_key: transaction.public_key.clone().into(), + public_key: transaction.public_key().clone().into(), allowance: *allowance, cost: total_cost, }) @@ -234,23 +235,23 @@ pub fn verify_and_charge_transaction( }; if let AccessKeyPermission::FunctionCall(ref function_call_permission) = access_key.permission { - if transaction.actions.len() != 1 { + if transaction.actions().len() != 1 { return Err(InvalidTxError::InvalidAccessKeyError( InvalidAccessKeyError::RequiresFullAccess, ) .into()); } - if let Some(Action::FunctionCall(ref function_call)) = transaction.actions.get(0) { + if let Some(Action::FunctionCall(ref function_call)) = transaction.actions().get(0) { if function_call.deposit > 0 { return Err(InvalidTxError::InvalidAccessKeyError( InvalidAccessKeyError::DepositWithFunctionCall, ) .into()); } - if transaction.receiver_id != function_call_permission.receiver_id { + if transaction.receiver_id() != &function_call_permission.receiver_id { return Err(InvalidTxError::InvalidAccessKeyError( InvalidAccessKeyError::ReceiverMismatch { - tx_receiver: transaction.receiver_id.clone(), + tx_receiver: transaction.receiver_id().clone(), ak_receiver: function_call_permission.receiver_id.clone(), }, ) @@ -277,7 +278,7 @@ pub fn verify_and_charge_transaction( } }; - set_access_key(state_update, signer_id.clone(), transaction.public_key.clone(), &access_key); + set_access_key(state_update, signer_id.clone(), transaction.public_key().clone(), &access_key); set_account(state_update, signer_id.clone(), &signer); Ok(VerificationResult { gas_burnt, gas_remaining, receipt_gas_price, burnt_amount }) @@ -292,16 +293,16 @@ pub(crate) fn validate_receipt( // We retain these checks here as to maintain backwards compatibility // with AccountId validation since we illegally parse an AccountId // in near-vm-logic/logic.rs#fn(VMLogic::read_and_parse_account_id) - AccountId::validate(receipt.predecessor_id.as_ref()).map_err(|_| { + AccountId::validate(receipt.predecessor_id().as_ref()).map_err(|_| { ReceiptValidationError::InvalidPredecessorId { - account_id: receipt.predecessor_id.to_string(), + account_id: receipt.predecessor_id().to_string(), } })?; - AccountId::validate(receipt.receiver_id.as_ref()).map_err(|_| { - ReceiptValidationError::InvalidReceiverId { account_id: receipt.receiver_id.to_string() } + AccountId::validate(receipt.receiver_id().as_ref()).map_err(|_| { + ReceiptValidationError::InvalidReceiverId { account_id: receipt.receiver_id().to_string() } })?; - match &receipt.receipt { + match receipt.receipt() { ReceiptEnum::Action(action_receipt) | ReceiptEnum::PromiseYield(action_receipt) => { validate_action_receipt(limit_config, action_receipt, current_protocol_version) } @@ -573,6 +574,7 @@ mod tests { use near_primitives::account::{AccessKey, FunctionCallPermission}; use near_primitives::action::delegate::{DelegateAction, NonDelegateAction}; use near_primitives::hash::{hash, CryptoHash}; + use near_primitives::receipt::ReceiptPriority; use near_primitives::test_utils::account_new; use near_primitives::transaction::{ CreateAccountAction, DeleteAccountAction, DeleteKeyAction, StakeAction, TransferAction, @@ -960,6 +962,7 @@ mod tests { deposit: 0, }))], CryptoHash::default(), + 0 ), RuntimeError::InvalidTxError(InvalidTxError::ActionsValidation( ActionsValidationError::TotalPrepaidGasExceeded { @@ -1122,6 +1125,7 @@ mod tests { deposit: 0, }))], CryptoHash::default(), + 0 ), true, None, @@ -1257,6 +1261,7 @@ mod tests { Action::CreateAccount(CreateAccountAction {}) ], CryptoHash::default(), + 0 ), true, None, @@ -1280,6 +1285,7 @@ mod tests { &*signer, vec![], CryptoHash::default(), + 0 ), true, None, @@ -1303,6 +1309,7 @@ mod tests { &*signer, vec![Action::CreateAccount(CreateAccountAction {})], CryptoHash::default(), + 0 ), true, None, @@ -1348,6 +1355,7 @@ mod tests { deposit: 0, })),], CryptoHash::default(), + 0 ), true, None, @@ -1396,6 +1404,7 @@ mod tests { deposit: 0, })),], CryptoHash::default(), + 0 ), true, None, @@ -1441,6 +1450,7 @@ mod tests { deposit: 100, })),], CryptoHash::default(), + 0 ), true, None, @@ -1465,6 +1475,7 @@ mod tests { &*signer, vec![Action::DeployContract(DeployContractAction { code: vec![1; 5] })], CryptoHash::default(), + 0 ); let transaction_size = transaction.get_size(); @@ -1509,7 +1520,7 @@ mod tests { let limit_config = test_limit_config(); validate_receipt( &limit_config, - &Receipt::new_balance_refund(&alice_account(), 10), + &Receipt::new_balance_refund(&alice_account(), 10, ReceiptPriority::NoPriority), PROTOCOL_VERSION, ) .expect("valid receipt"); diff --git a/runtime/runtime/tests/runtime_group_tools/mod.rs b/runtime/runtime/tests/runtime_group_tools/mod.rs index 25ed48d00ad..4ad7b9fd72b 100644 --- a/runtime/runtime/tests/runtime_group_tools/mod.rs +++ b/runtime/runtime/tests/runtime_group_tools/mod.rs @@ -257,7 +257,7 @@ impl RuntimeGroup { .0 .lock() .unwrap() - .get_mut(&transaction.transaction.signer_id) + .get_mut(transaction.transaction.signer_id()) .unwrap() .incoming_transactions .push(transaction); @@ -323,7 +323,7 @@ impl RuntimeGroup { mailbox.incoming_transactions.clear(); group.transaction_logs.lock().unwrap().extend(transaction_results); for new_receipt in new_receipts { - let locked_other_mailbox = mailboxes.get_mut(&new_receipt.receiver_id).unwrap(); + let locked_other_mailbox = mailboxes.get_mut(new_receipt.receiver_id()).unwrap(); locked_other_mailbox.incoming_receipts.push(new_receipt); } group.mailboxes.1.notify_all(); @@ -410,9 +410,9 @@ macro_rules! assert_receipts { $($action_name:ident, $action_pat:pat, $action_assert:block ),+ => [ $($produced_receipt:ident),*] ) => { let r = $group.get_receipt($to, $receipt); - assert_eq!(r.predecessor_id, $from); - assert_eq!(r.receiver_id, $to); - match &r.receipt { + assert_eq!(r.predecessor_id().clone(), $from); + assert_eq!(r.receiver_id().clone(), $to); + match r.receipt() { $receipt_pat => { $receipt_assert tuplet!(( $($action_name),* ) = $actions_name, "Incorrect number of actions"); diff --git a/runtime/runtime/tests/test_async_calls.rs b/runtime/runtime/tests/test_async_calls.rs index e8fe09ed609..0d8188df758 100644 --- a/runtime/runtime/tests/test_async_calls.rs +++ b/runtime/runtime/tests/test_async_calls.rs @@ -37,6 +37,7 @@ fn test_simple_func_call() { deposit: 0, }))], CryptoHash::default(), + 0 ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -83,6 +84,7 @@ fn test_single_promise_no_callback() { deposit: 0, }))], CryptoHash::default(), + 0 ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -149,6 +151,7 @@ fn test_single_promise_with_callback() { deposit: 0, }))], CryptoHash::default(), + 0 ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -233,6 +236,7 @@ fn test_two_promises_no_callbacks() { deposit: 0, }))], CryptoHash::default(), + 0 ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -327,6 +331,7 @@ fn test_two_promises_with_two_callbacks() { deposit: 0, }))], CryptoHash::default(), + 0 ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -418,6 +423,7 @@ fn test_single_promise_no_callback_batch() { deposit: 0, }))], CryptoHash::default(), + 0, ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -490,6 +496,7 @@ fn test_single_promise_with_callback_batch() { deposit: 0, }))], CryptoHash::default(), + 0 ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -564,6 +571,7 @@ fn test_simple_transfer() { deposit: 0, }))], CryptoHash::default(), + 0 ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -631,6 +639,7 @@ fn test_create_account_with_transfer_and_full_key() { deposit: 0, }))], CryptoHash::default(), + 0 ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -743,6 +752,7 @@ fn test_account_factory() { deposit: 0, }))], CryptoHash::default(), + 0 ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -889,6 +899,7 @@ fn test_create_account_add_key_call_delete_key_delete_account() { deposit: 0, }))], CryptoHash::default(), + 0 ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -983,6 +994,7 @@ fn test_transfer_64len_hex() { deposit: 0, }))], CryptoHash::default(), + 0, ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -1049,6 +1061,7 @@ fn test_create_transfer_64len_hex_fail() { deposit: 0, }))], CryptoHash::default(), + 0 ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); diff --git a/test-utils/runtime-tester/src/run_test.rs b/test-utils/runtime-tester/src/run_test.rs index c885a525c65..e19b3012471 100644 --- a/test-utils/runtime-tester/src/run_test.rs +++ b/test-utils/runtime-tester/src/run_test.rs @@ -185,6 +185,7 @@ impl TransactionConfig { &self.signer, self.actions.clone(), *last_block.hash(), + 0 ) } } diff --git a/tools/fork-network/src/single_shard_storage_mutator.rs b/tools/fork-network/src/single_shard_storage_mutator.rs index 7206dda2e91..70bf695c689 100644 --- a/tools/fork-network/src/single_shard_storage_mutator.rs +++ b/tools/fork-network/src/single_shard_storage_mutator.rs @@ -94,8 +94,8 @@ impl SingleShardStorageMutator { pub(crate) fn set_postponed_receipt(&mut self, receipt: &Receipt) -> anyhow::Result<()> { self.set( TrieKey::PostponedReceipt { - receiver_id: receipt.receiver_id.clone(), - receipt_id: receipt.receipt_id, + receiver_id: receipt.receiver_id().clone(), + receipt_id: *receipt.receipt_id(), }, borsh::to_vec(&receipt)?, ) @@ -103,8 +103,8 @@ impl SingleShardStorageMutator { pub(crate) fn delete_postponed_receipt(&mut self, receipt: &Receipt) -> anyhow::Result<()> { self.remove(TrieKey::PostponedReceipt { - receiver_id: receipt.receiver_id.clone(), - receipt_id: receipt.receipt_id, + receiver_id: receipt.receiver_id().clone(), + receipt_id: *receipt.receipt_id(), }) } diff --git a/tools/mirror/src/chain_tracker.rs b/tools/mirror/src/chain_tracker.rs index 29641131bdc..eecbd84c7d5 100644 --- a/tools/mirror/src/chain_tracker.rs +++ b/tools/mirror/src/chain_tracker.rs @@ -45,14 +45,14 @@ impl TxSendInfo { target_height: BlockHeight, now: Instant, ) -> Self { - let target_signer_id = if &tx.source_signer_id != &tx.target_tx.transaction.signer_id { - Some(tx.target_tx.transaction.signer_id.clone()) + let target_signer_id = if &tx.source_signer_id != tx.target_tx.transaction.signer_id() { + Some(tx.target_tx.transaction.signer_id().clone()) } else { None }; - let target_receiver_id = if &tx.source_receiver_id != &tx.target_tx.transaction.receiver_id + let target_receiver_id = if &tx.source_receiver_id != tx.target_tx.transaction.receiver_id() { - Some(tx.target_tx.transaction.receiver_id.clone()) + Some(tx.target_tx.transaction.receiver_id().clone()) } else { None }; @@ -68,7 +68,7 @@ impl TxSendInfo { actions: tx .target_tx .transaction - .actions + .actions() .iter() .map(|a| a.as_ref().to_string()) .collect::>(), @@ -417,8 +417,8 @@ impl TxTracker { let info = self .nonces .get_mut(&( - tx.target_tx.transaction.signer_id.clone(), - tx.target_tx.transaction.public_key.clone(), + tx.target_tx.transaction.signer_id().clone(), + tx.target_tx.transaction.public_key().clone(), )) .unwrap(); info.queued_txs.insert(tx_ref.clone()); @@ -435,8 +435,8 @@ impl TxTracker { let info = self .nonces .get_mut(&( - tx.target_tx.signer_id.clone(), - tx.target_tx.public_key.clone(), + tx.target_tx.signer_id().clone(), + tx.target_tx.public_key().clone(), )) .unwrap(); info.txs_awaiting_nonce.insert(tx_ref.clone()); @@ -478,7 +478,7 @@ impl TxTracker { for tx in c.txs.iter_mut() { if let TargetChainTx::AwaitingNonce(t) = tx { needed_access_keys - .insert((t.target_tx.signer_id.clone(), t.target_tx.public_key.clone())); + .insert((t.target_tx.signer_id().clone(), t.target_tx.public_key().clone())); } } } @@ -501,12 +501,12 @@ impl TxTracker { TargetChainTx::Ready(t) => { tracing::debug!( target: "mirror", "Prepared {} for ({}, {:?}) with nonce {} even though there are still pending outcomes that may affect the access key", - &t.provenance, &t.target_tx.transaction.signer_id, &t.target_tx.transaction.public_key, t.target_tx.transaction.nonce + &t.provenance, t.target_tx.transaction.signer_id(), t.target_tx.transaction.public_key(), t.target_tx.transaction.nonce() ); self.nonces .get_mut(&( - t.target_tx.transaction.signer_id.clone(), - t.target_tx.transaction.public_key.clone(), + t.target_tx.transaction.signer_id().clone(), + t.target_tx.transaction.public_key().clone(), )) .unwrap() .txs_awaiting_nonce @@ -515,12 +515,12 @@ impl TxTracker { TargetChainTx::AwaitingNonce(t) => { tracing::warn!( target: "mirror", "Could not prepare {} for ({}, {:?}). Nonce unknown", - &t.provenance, &t.target_tx.signer_id, &t.target_tx.public_key, + &t.provenance, t.target_tx.signer_id(), t.target_tx.public_key(), ); self.nonces .get_mut(&( - t.target_tx.signer_id.clone(), - t.target_tx.public_key.clone(), + t.target_tx.signer_id().clone(), + t.target_tx.public_key().clone(), )) .unwrap() .txs_awaiting_nonce @@ -746,7 +746,7 @@ impl TxTracker { tx.try_set_nonce(nonce); match tx { TargetChainTx::Ready(t) => { - tracing::debug!(target: "mirror", "set nonce for {:?}'s {} to {}", access_key, r, t.target_tx.transaction.nonce); + tracing::debug!(target: "mirror", "set nonce for {:?}'s {} to {}", access_key, r, t.target_tx.transaction.nonce()); } _ => { tracing::warn!(target: "mirror", "Couldn't set nonce for {:?}'s {}", access_key, r); @@ -925,12 +925,12 @@ impl TxTracker { { tracing::debug!( target: "mirror", "Successfully sent transaction {} for {}: {:?}", - &hash, &tx.provenance, &tx.target_tx.transaction.actions, + &hash, &tx.provenance, tx.target_tx.transaction.actions(), ); } let access_key = ( - tx.target_tx.transaction.signer_id.clone(), - tx.target_tx.transaction.public_key.clone(), + tx.target_tx.transaction.signer_id().clone(), + tx.target_tx.transaction.public_key().clone(), ); let source_height = tx_ref.as_ref().map(|t| t.source_height); // TODO: don't keep adding txs if we're not ever finding them on chain, since we'll OOM eventually @@ -939,14 +939,14 @@ impl TxTracker { let txs = self.txs_by_signer.entry(access_key.clone()).or_default(); if let Some(highest_nonce) = txs.iter().next_back() { - if highest_nonce.nonce > tx.target_tx.transaction.nonce { + if highest_nonce.nonce > tx.target_tx.transaction.nonce() { tracing::warn!( target: "mirror", "transaction sent with out of order nonce: {}: {}. Sent so far: {:?}", - &hash, tx.target_tx.transaction.nonce, txs + &hash, tx.target_tx.transaction.nonce(), txs ); } } - if !txs.insert(TxId { hash, nonce: tx.target_tx.transaction.nonce }) { + if !txs.insert(TxId { hash, nonce: tx.target_tx.transaction.nonce() }) { tracing::warn!(target: "mirror", "inserted tx {} twice into txs_by_signer", &hash); } @@ -995,15 +995,15 @@ impl TxTracker { let mut t = crate::read_target_nonce( db, - &tx.target_tx.transaction.signer_id, - &tx.target_tx.transaction.public_key, + tx.target_tx.transaction.signer_id(), + tx.target_tx.transaction.public_key(), )? .unwrap(); - t.nonce = std::cmp::max(t.nonce, Some(tx.target_tx.transaction.nonce)); + t.nonce = std::cmp::max(t.nonce, Some(tx.target_tx.transaction.nonce())); crate::put_target_nonce( db, - &tx.target_tx.transaction.signer_id, - &tx.target_tx.transaction.public_key, + tx.target_tx.transaction.signer_id(), + tx.target_tx.transaction.public_key(), &t, )?; let info = self.nonces.get_mut(&access_key).unwrap(); @@ -1097,7 +1097,7 @@ impl TxTracker { target_tx.try_set_nonce(None); match target_tx { TargetChainTx::Ready(t) => { - tracing::debug!(target: "mirror", "After skipping {} setting nonce for {:?}'s {} to {}", tx_ref, &access_key, r, t.target_tx.transaction.nonce); + tracing::debug!(target: "mirror", "After skipping {} setting nonce for {:?}'s {} to {}", tx_ref, &access_key, r, t.target_tx.transaction.nonce()); } _ => { tracing::warn!(target: "mirror", "After skipping {} could not set nonce for {:?}'s {}", tx_ref, &access_key, r); @@ -1121,7 +1121,7 @@ impl TxTracker { } } } - let access_key = (tx.signer_id.clone(), tx.public_key.clone()); + let access_key = (tx.signer_id().clone(), tx.public_key().clone()); let info = self.nonces.get_mut(&access_key).unwrap(); if info.last_height <= Some(tx_ref.source_height) { access_keys_to_remove.insert(access_key); diff --git a/tools/mirror/src/genesis.rs b/tools/mirror/src/genesis.rs index a84d05d2eb2..dd6f0382ed4 100644 --- a/tools/mirror/src/genesis.rs +++ b/tools/mirror/src/genesis.rs @@ -155,9 +155,9 @@ pub fn map_receipt( secret: Option<&[u8; crate::secret::SECRET_LEN]>, default_key: &PublicKey, ) { - receipt.predecessor_id = crate::key_mapping::map_account(&receipt.predecessor_id, secret); - receipt.receiver_id = crate::key_mapping::map_account(&receipt.receiver_id, secret); - match &mut receipt.receipt { + receipt.set_predecessor_id(crate::key_mapping::map_account(receipt.predecessor_id(), secret)); + receipt.set_receiver_id(crate::key_mapping::map_account(receipt.receiver_id(), secret)); + match receipt.receipt_mut() { ReceiptEnum::Action(r) | ReceiptEnum::PromiseYield(r) => { map_action_receipt(r, secret, default_key); } @@ -268,7 +268,7 @@ mod test { use near_primitives::account::{AccessKeyPermission, FunctionCallPermission}; use near_primitives::action::delegate::{DelegateAction, SignedDelegateAction}; use near_primitives::hash::CryptoHash; - use near_primitives::receipt::{ActionReceipt, Receipt, ReceiptEnum}; + use near_primitives::receipt::{ActionReceipt, Receipt, ReceiptEnum, ReceiptV0}; use near_primitives::transaction::{Action, AddKeyAction, CreateAccountAction}; use near_primitives_core::account::AccessKey; @@ -276,7 +276,7 @@ mod test { fn test_map_receipt() { let default_key = crate::key_mapping::default_extra_key(None).public_key(); - let mut receipt0 = Receipt { + let mut receipt0 = Receipt::V0(ReceiptV0 { predecessor_id: "foo.near".parse().unwrap(), receiver_id: "foo.foo.near".parse().unwrap(), receipt_id: CryptoHash::default(), @@ -305,8 +305,8 @@ mod test { })), ], }), - }; - let want_receipt0 = Receipt { + }); + let want_receipt0 = Receipt::V0(ReceiptV0 { predecessor_id: "foo.near".parse().unwrap(), receiver_id: "foo.foo.near".parse().unwrap(), receipt_id: CryptoHash::default(), @@ -339,7 +339,7 @@ mod test { })), ], }), - }; + }); let secret_key = SecretKey::from_random(KeyType::ED25519); let delegate_action = DelegateAction { @@ -360,7 +360,7 @@ mod test { let tx_hash = delegate_action.get_nep461_hash(); let signature = secret_key.sign(tx_hash.as_ref()); - let mut receipt1 = Receipt { + let mut receipt1 = Receipt::V0(ReceiptV0 { predecessor_id: "757a45019f9a3e5bd475586c31f63d6e15d50f5366caf4643f6f69731a222cad" .parse() .unwrap(), @@ -383,7 +383,7 @@ mod test { signature, }))], }), - }; + }); let mapped_secret_key = crate::key_mapping::map_key(&secret_key.public_key(), None); let delegate_action = DelegateAction { @@ -403,7 +403,7 @@ mod test { }; let tx_hash = delegate_action.get_nep461_hash(); let signature = mapped_secret_key.sign(tx_hash.as_ref()); - let want_receipt1 = Receipt { + let want_receipt1 = Receipt::V0(ReceiptV0 { predecessor_id: "3f8c3be8929e5fa61907f13a6247e7e452b92bb7d224cf691a9aa67814eb509b" .parse() .unwrap(), @@ -426,7 +426,7 @@ mod test { signature, }))], }), - }; + }); crate::genesis::map_receipt(&mut receipt0, None, &default_key); assert_eq!(receipt0, want_receipt0); diff --git a/tools/mirror/src/lib.rs b/tools/mirror/src/lib.rs index 809582269c3..0c98ebd012b 100644 --- a/tools/mirror/src/lib.rs +++ b/tools/mirror/src/lib.rs @@ -261,28 +261,28 @@ impl SourceTransaction { fn public_key(&self) -> &PublicKey { match self { - Self::Tx(tx) => &tx.transaction.public_key, + Self::Tx(tx) => tx.transaction.public_key(), Self::TxView(tx) => &tx.public_key, } } fn signer_id(&self) -> &AccountId { match self { - Self::Tx(tx) => &tx.transaction.signer_id, + Self::Tx(tx) => tx.transaction.signer_id(), Self::TxView(tx) => &tx.signer_id, } } fn receiver_id(&self) -> &AccountId { match self { - Self::Tx(tx) => &tx.transaction.receiver_id, + Self::Tx(tx) => tx.transaction.receiver_id(), Self::TxView(tx) => &tx.receiver_id, } } fn actions<'a>(&'a self) -> Cow<'a, [Action]> { match self { - Self::Tx(tx) => Cow::Borrowed(&tx.transaction.actions), + Self::Tx(tx) => Cow::Borrowed(tx.transaction.actions()), Self::TxView(tx) => { Cow::Owned(tx.actions.iter().map(|a| a.clone().try_into().unwrap()).collect()) } @@ -587,8 +587,8 @@ impl TxAwaitingNonce { nonce_updates: HashSet<(AccountId, PublicKey)>, ) -> Self { let mut target_tx = - Transaction::new(target_signer_id, target_public_key, target_receiver_id, 0, *ref_hash); - target_tx.actions = actions; + Transaction::new(target_signer_id, target_public_key, target_receiver_id, 0, *ref_hash, 0); + *target_tx.actions_mut() = actions; Self { source_signer_id, source_receiver_id, @@ -634,8 +634,9 @@ impl MappedTx { target_receiver_id, nonce, *ref_hash, + 0 ); - target_tx.actions = actions; + *target_tx.actions_mut() = actions; let target_tx = SignedTransaction::new( target_secret_key.sign(&target_tx.get_hash_and_size().0.as_ref()), target_tx, @@ -652,7 +653,7 @@ impl MappedTx { fn inc_nonce(&mut self, target_secret_key: &SecretKey) { let mut tx = self.target_tx.transaction.clone(); - tx.nonce += 1; + *tx.nonce_mut() += 1; self.target_tx = SignedTransaction::new(target_secret_key.sign(&tx.get_hash_and_size().0.as_ref()), tx); } @@ -668,7 +669,7 @@ impl TargetChainTx { fn set_nonce(&mut self, nonce: Nonce) { match self { Self::AwaitingNonce(t) => { - t.target_tx.nonce = nonce; + *t.target_tx.nonce_mut() = nonce; let target_tx = SignedTransaction::new( t.target_secret_key.sign(&t.target_tx.get_hash_and_size().0.as_ref()), t.target_tx.clone(), @@ -758,7 +759,7 @@ impl TargetChainTx { fn target_nonce(&self) -> TargetNonce { match self { Self::Ready(t) => TargetNonce { - nonce: Some(t.target_tx.transaction.nonce), + nonce: Some(t.target_tx.transaction.nonce()), pending_outcomes: HashSet::new(), }, Self::AwaitingNonce(t) => t.target_nonce.clone(), @@ -925,7 +926,7 @@ impl TxMirror { // only once instance of this code will run, but this is the place to detect if that's not the case. tracing::error!( target: "mirror", "Tried to send an invalid tx for ({}, {:?}) from {}: {:?}", - &tx.target_tx.transaction.signer_id, &tx.target_tx.transaction.public_key, &tx.provenance, e + tx.target_tx.transaction.signer_id(), tx.target_tx.transaction.public_key(), &tx.provenance, e ); crate::metrics::TRANSACTIONS_SENT.with_label_values(&["invalid"]).inc(); } @@ -944,7 +945,7 @@ impl TxMirror { // TODO: here we should just save this transaction for later and send it when it's known tracing::warn!( target: "mirror", "skipped sending transaction for ({}, {:?}) because valid target chain nonce not known", - &tx.target_tx.signer_id, &tx.target_tx.public_key + tx.target_tx.signer_id(), tx.target_tx.public_key() ); } } @@ -1299,10 +1300,10 @@ impl TxMirror { Err(ChainError::Other(e)) => return Err(e), }; - if let ReceiptEnum::Action(r) | ReceiptEnum::PromiseYield(r) = &receipt.receipt { - if (provenance.is_create_account() && receipt.predecessor_id == receipt.receiver_id) + if let ReceiptEnum::Action(r) | ReceiptEnum::PromiseYield(r) = receipt.receipt() { + if (provenance.is_create_account() && receipt.predecessor_id() == receipt.receiver_id()) || (!provenance.is_create_account() - && receipt.predecessor_id != receipt.receiver_id) + && receipt.predecessor_id() != receipt.receiver_id()) { continue; } @@ -1328,19 +1329,19 @@ impl TxMirror { if account_created { tracing::warn!( target: "mirror", "for receipt {} predecessor and receiver are the same but there's a create account in the actions: {:?}", - &receipt.receipt_id, &r.actions, + receipt.receipt_id(), &r.actions, ); } } let outcome = self .source_chain_access .get_outcome(TransactionOrReceiptId::Receipt { - receipt_id: receipt.receipt_id, - receiver_id: receipt.receiver_id.clone(), + receipt_id: *receipt.receipt_id(), + receiver_id: receipt.receiver_id().clone(), }) .await .with_context(|| { - format!("failed fetching outcome for receipt {}", receipt.receipt_id) + format!("failed fetching outcome for receipt {}", receipt.receipt_id()) })?; if !execution_status_good(&outcome.outcome.status) { continue; @@ -1350,8 +1351,8 @@ impl TxMirror { tracker, outcome.block_hash, txs, - receipt.predecessor_id.clone(), - receipt.receiver_id.clone(), + receipt.predecessor_id().clone(), + receipt.receiver_id().clone(), &r.actions, ref_hash, provenance, @@ -1413,13 +1414,13 @@ impl TxMirror { tracker: &mut crate::chain_tracker::TxTracker, txs: &mut Vec, ) -> anyhow::Result<()> { - if let ReceiptEnum::Action(r) | ReceiptEnum::PromiseYield(r) = &receipt.receipt { + if let ReceiptEnum::Action(r) | ReceiptEnum::PromiseYield(r) = receipt.receipt() { if r.actions.iter().any(|a| matches!(a, Action::FunctionCall(_))) { self.add_function_call_keys( tracker, txs, - &receipt.receipt_id, - &receipt.receiver_id, + receipt.receipt_id(), + receipt.receiver_id(), ref_hash, provenance, source_height, diff --git a/tools/state-viewer/src/apply_chain_range.rs b/tools/state-viewer/src/apply_chain_range.rs index e4ee3e5ac58..477c5f627b7 100644 --- a/tools/state-viewer/src/apply_chain_range.rs +++ b/tools/state-viewer/src/apply_chain_range.rs @@ -221,7 +221,7 @@ fn apply_block_from_range( if only_contracts { let mut has_contracts = false; for tx in chunk.transactions() { - for action in &tx.transaction.actions { + for action in tx.transaction.actions() { has_contracts = has_contracts || matches!(action, Action::FunctionCall(_) | Action::DeployContract(_)); } diff --git a/tools/state-viewer/src/apply_chunk.rs b/tools/state-viewer/src/apply_chunk.rs index 80130fcce63..14da7232036 100644 --- a/tools/state-viewer/src/apply_chunk.rs +++ b/tools/state-viewer/src/apply_chunk.rs @@ -186,7 +186,7 @@ fn find_tx_or_receipt( let shard_layout = epoch_manager.get_shard_layout_from_prev_block(chunk.prev_block())?; let to_shard = - shard_layout::account_id_to_shard_id(&receipt.receiver_id, &shard_layout); + shard_layout::account_id_to_shard_id(receipt.receiver_id(), &shard_layout); return Ok(Some((HashType::Receipt, to_shard))); } } @@ -394,7 +394,7 @@ fn apply_receipt_in_chunk( let shard_layout = epoch_manager.get_shard_layout_from_prev_block(chunk.prev_block())?; let to_shard = shard_layout::account_id_to_shard_id( - &receipt.receiver_id, + receipt.receiver_id(), &shard_layout, ); to_apply.insert((height, to_shard)); @@ -681,7 +681,7 @@ mod test { for receipt in chunk.prev_outgoing_receipts() { let to_shard = shard_layout::account_id_to_shard_id( - &receipt.receiver_id, + receipt.receiver_id(), &shard_layout, ); diff --git a/tools/state-viewer/src/contract_accounts.rs b/tools/state-viewer/src/contract_accounts.rs index 025fe5b4719..fce79dca2e1 100644 --- a/tools/state-viewer/src/contract_accounts.rs +++ b/tools/state-viewer/src/contract_accounts.rs @@ -295,16 +295,16 @@ fn try_find_actions_spawned_by_receipt( .map_err(|e| ContractAccountError::InvalidReceipt(e, key))?; // Skip refunds. - if receipt.receiver_id.is_system() { + if receipt.receiver_id().is_system() { return Ok(()); } // Note: We could use the entry API here to avoid the double hash, but we // would have to clone the key string. It's unclear which is better, I will // avoid the entry API because normal contains/get_mut seems simpler. - if accounts.contains_key(&receipt.receiver_id) { + if accounts.contains_key(receipt.receiver_id()) { // yes, this is a contract in our map (skip/select filtering has already been applied when constructing the map) - let entry = accounts.get_mut(&receipt.receiver_id).unwrap(); + let entry = accounts.get_mut(receipt.receiver_id()).unwrap(); if filter.receipts_in { *entry.receipts_in.get_or_insert(0) += 1; } @@ -327,7 +327,7 @@ fn try_find_actions_spawned_by_receipt( let outgoing_receipt = maybe_outgoing_receipt.ok_or_else(|| { ContractAccountError::MissingOutgoingReceipt(*outgoing_receipt_id) })?; - match outgoing_receipt.receipt { + match outgoing_receipt.receipt() { ReceiptEnum::Action(action_receipt) | ReceiptEnum::PromiseYield(action_receipt) => { for action in &action_receipt.actions { @@ -493,7 +493,7 @@ mod tests { use borsh::BorshSerialize; use near_crypto::{InMemorySigner, Signer}; use near_primitives::hash::CryptoHash; - use near_primitives::receipt::{ActionReceipt, Receipt, ReceiptEnum}; + use near_primitives::receipt::{ActionReceipt, Receipt, ReceiptEnum, ReceiptV0}; use near_primitives::transaction::{ Action, CreateAccountAction, DeployContractAction, ExecutionMetadata, ExecutionOutcome, ExecutionOutcomeWithProof, ExecutionStatus, FunctionCallAction, TransferAction, @@ -722,7 +722,7 @@ mod tests { let sender_id: AccountId = sender.parse().unwrap(); let signer = InMemorySigner::from_seed(sender_id.clone(), near_crypto::KeyType::ED25519, "seed"); - Receipt { + Receipt::V0(ReceiptV0 { predecessor_id: sender_id.clone(), receiver_id: receiver.parse().unwrap(), receipt_id: CryptoHash::default(), @@ -734,6 +734,6 @@ mod tests { input_data_ids: vec![], actions, }), - } + }) } } diff --git a/tools/state-viewer/src/state_dump.rs b/tools/state-viewer/src/state_dump.rs index 5f3e1fa2ea3..5caddf4203a 100644 --- a/tools/state-viewer/src/state_dump.rs +++ b/tools/state-viewer/src/state_dump.rs @@ -458,6 +458,7 @@ mod test { code: near_test_contracts::backwards_compatible_rs_contract().to_vec(), })], genesis_hash, + 0 ); let tx01 = SignedTransaction::stake( 1, diff --git a/tools/state-viewer/src/tx_dump.rs b/tools/state-viewer/src/tx_dump.rs index e69bee4d1a1..291f18f7f5c 100644 --- a/tools/state-viewer/src/tx_dump.rs +++ b/tools/state-viewer/src/tx_dump.rs @@ -35,6 +35,6 @@ fn should_include_signed_transaction( ) -> bool { match select_account_ids { None => true, - Some(specified_ids) => specified_ids.contains(&signed_transaction.transaction.receiver_id), + Some(specified_ids) => specified_ids.contains(signed_transaction.transaction.receiver_id()), } } From bad66172fee3836c860d63e42161d0043539719a Mon Sep 17 00:00:00 2001 From: Bowen Wang Date: Fri, 3 May 2024 09:48:14 -0700 Subject: [PATCH 2/8] fix serialization --- chain/chain/src/chain_update.rs | 5 +- chain/chain/src/garbage_collection.rs | 7 +- chain/chain/src/runtime/tests.rs | 4 +- chain/chain/src/test_utils/kv_runtime.rs | 8 +- chain/client/src/client.rs | 2 +- chain/client/src/test_utils/test_env.rs | 4 +- chain/rosetta-rpc/src/lib.rs | 35 +++-- core/primitives/benches/serialization.rs | 4 +- core/primitives/src/errors.rs | 5 + core/primitives/src/receipt.rs | 110 ++++++++++--- core/primitives/src/test_utils.rs | 56 +++++-- core/primitives/src/transaction.rs | 146 ++++++++++++++---- core/store/src/test_utils.rs | 19 ++- .../src/tests/client/benchmarks.rs | 2 +- .../account_id_in_function_call_permission.rs | 11 +- .../client/features/chunk_nodes_cache.rs | 2 +- .../src/tests/client/features/flat_storage.rs | 4 +- .../features/increase_storage_compute_cost.rs | 2 +- .../features/lower_storage_key_limit.rs | 27 ++-- .../src/tests/client/features/nearvm.rs | 11 +- .../features/storage_proof_size_limit.rs | 4 +- .../tests/client/features/wallet_contract.rs | 8 +- .../client/features/zero_balance_account.rs | 4 +- .../src/tests/client/process_blocks.rs | 14 +- .../src/tests/client/resharding.rs | 7 +- .../src/tests/runtime/deployment.rs | 2 +- integration-tests/src/tests/test_errors.rs | 4 +- integration-tests/src/user/mod.rs | 2 +- .../src/transaction_builder.rs | 2 +- runtime/runtime/src/actions.rs | 18 ++- runtime/runtime/src/balance_checker.rs | 20 ++- runtime/runtime/src/config.rs | 8 +- runtime/runtime/src/lib.rs | 42 +++-- runtime/runtime/src/verifier.rs | 35 ++++- .../runtime/tests/runtime_group_tools/mod.rs | 3 +- runtime/runtime/tests/test_async_calls.rs | 22 +-- test-utils/runtime-tester/src/run_test.rs | 2 +- tools/mirror/src/chain_tracker.rs | 6 +- tools/mirror/src/lib.rs | 15 +- tools/state-viewer/src/state_dump.rs | 2 +- 40 files changed, 492 insertions(+), 192 deletions(-) diff --git a/chain/chain/src/chain_update.rs b/chain/chain/src/chain_update.rs index 82e946fb743..fc9d815bcd7 100644 --- a/chain/chain/src/chain_update.rs +++ b/chain/chain/src/chain_update.rs @@ -135,7 +135,10 @@ impl<'a> ChainUpdate<'a> { let outgoing_receipts = outgoing_receipts .iter() .map(|receipt| { - (*receipt.receipt_id(), account_id_to_shard_id(receipt.receiver_id(), &shard_layout)) + ( + *receipt.receipt_id(), + account_id_to_shard_id(receipt.receiver_id(), &shard_layout), + ) }) .collect(); Ok(outgoing_receipts) diff --git a/chain/chain/src/garbage_collection.rs b/chain/chain/src/garbage_collection.rs index a044fcd81ce..e552515433a 100644 --- a/chain/chain/src/garbage_collection.rs +++ b/chain/chain/src/garbage_collection.rs @@ -852,10 +852,9 @@ impl<'a> ChainStoreUpdate<'a> { fn gc_outgoing_receipts(&mut self, block_hash: &CryptoHash, shard_id: ShardId) { let mut store_update = self.store().store_update(); - match self - .get_outgoing_receipts(block_hash, shard_id) - .map(|receipts| receipts.iter().map(|receipt| *receipt.receipt_id()).collect::>()) - { + match self.get_outgoing_receipts(block_hash, shard_id).map(|receipts| { + receipts.iter().map(|receipt| *receipt.receipt_id()).collect::>() + }) { Ok(receipt_ids) => { for receipt_id in receipt_ids { let key: Vec = receipt_id.into(); diff --git a/chain/chain/src/runtime/tests.rs b/chain/chain/src/runtime/tests.rs index c5d76004440..624de60801a 100644 --- a/chain/chain/src/runtime/tests.rs +++ b/chain/chain/src/runtime/tests.rs @@ -59,7 +59,7 @@ fn stake( vec![Action::Stake(Box::new(StakeAction { stake, public_key: sender.public_key() }))], // runtime does not validate block history CryptoHash::default(), - 0 + 0, ) } @@ -1386,7 +1386,7 @@ fn test_delete_account_after_unstake() { })], // runtime does not validate block history CryptoHash::default(), - 0 + 0, ); env.step_default(vec![delete_account_transaction]); for _ in 15..=17 { diff --git a/chain/chain/src/test_utils/kv_runtime.rs b/chain/chain/src/test_utils/kv_runtime.rs index 590586c01e3..5a809ca51ee 100644 --- a/chain/chain/src/test_utils/kv_runtime.rs +++ b/chain/chain/src/test_utils/kv_runtime.rs @@ -1118,7 +1118,10 @@ impl RuntimeAdapter for KeyValueRuntime { if let ReceiptEnum::Action(action) | ReceiptEnum::PromiseYield(action) = receipt.receipt() { - assert_eq!(account_id_to_shard_id(receipt.receiver_id(), self.num_shards), shard_id); + assert_eq!( + account_id_to_shard_id(receipt.receiver_id(), self.num_shards), + shard_id + ); if !state.receipt_nonces.contains(receipt.receipt_id()) { state.receipt_nonces.insert(*receipt.receipt_id()); if let Action::Transfer(TransferAction { deposit }) = action.actions[0] { @@ -1146,7 +1149,8 @@ impl RuntimeAdapter for KeyValueRuntime { if transaction.transaction.actions().is_empty() { continue; } - if let Action::Transfer(TransferAction { deposit }) = transaction.transaction.actions()[0] + if let Action::Transfer(TransferAction { deposit }) = + transaction.transaction.actions()[0] { if !state.tx_nonces.contains(&AccountNonce( transaction.transaction.receiver_id().clone(), diff --git a/chain/client/src/client.rs b/chain/client/src/client.rs index 7249345ec61..7af57c72e19 100644 --- a/chain/client/src/client.rs +++ b/chain/client/src/client.rs @@ -973,7 +973,7 @@ impl Client { "other".parse().unwrap(), 3, prev_block_hash, - 0 + 0, ), )); if txs.storage_proof.is_none() { diff --git a/chain/client/src/test_utils/test_env.rs b/chain/client/src/test_utils/test_env.rs index db84e8132b7..0391ac6f0f7 100644 --- a/chain/client/src/test_utils/test_env.rs +++ b/chain/client/src/test_utils/test_env.rs @@ -678,7 +678,7 @@ impl TestEnv { signer, actions, tip.last_block_hash, - 0 + 0, ) } @@ -717,7 +717,7 @@ impl TestEnv { &relayer_signer, vec![Action::Delegate(Box::new(signed_delegate_action))], tip.last_block_hash, - 0 + 0, ) } diff --git a/chain/rosetta-rpc/src/lib.rs b/chain/rosetta-rpc/src/lib.rs index c014e0e5464..99965c02e77 100644 --- a/chain/rosetta-rpc/src/lib.rs +++ b/chain/rosetta-rpc/src/lib.rs @@ -650,19 +650,21 @@ async fn construction_payloads( } = operations.try_into()?; let models::ConstructionMetadata { recent_block_hash, signer_public_access_key_nonce } = metadata; - let unsigned_transaction = near_primitives::transaction::Transaction::V0(near_primitives::transaction::TransactionV0 { - block_hash: recent_block_hash.parse().map_err(|err| { - errors::ErrorKind::InvalidInput(format!( - "block hash could not be parsed due to: {:?}", - err - )) - })?, - signer_id: signer_account_id.clone(), - public_key: signer_public_access_key.clone(), - nonce: signer_public_access_key_nonce, - receiver_id: receiver_account_id, - actions, - }); + let unsigned_transaction = near_primitives::transaction::Transaction::V0( + near_primitives::transaction::TransactionV0 { + block_hash: recent_block_hash.parse().map_err(|err| { + errors::ErrorKind::InvalidInput(format!( + "block hash could not be parsed due to: {:?}", + err + )) + })?, + signer_id: signer_account_id.clone(), + public_key: signer_public_access_key.clone(), + nonce: signer_public_access_key_nonce, + receiver_id: receiver_account_id, + actions, + }, + ); let (transaction_hash, _) = unsigned_transaction.get_hash_and_size(); @@ -749,8 +751,11 @@ async fn construction_parse( let account_identifier_signers = if signed { vec![transaction.signer_id().clone().into()] } else { vec![] }; - let near_actions = - crate::adapters::NearActions { sender_account_id: transaction.signer_id().clone(), receiver_account_id: transaction.receiver_id().clone(), actions: transaction.take_actions() }; + let near_actions = crate::adapters::NearActions { + sender_account_id: transaction.signer_id().clone(), + receiver_account_id: transaction.receiver_id().clone(), + actions: transaction.take_actions(), + }; Ok(Json(models::ConstructionParseResponse { account_identifier_signers, diff --git a/core/primitives/benches/serialization.rs b/core/primitives/benches/serialization.rs index fed4d75128e..4ec41c1ccfd 100644 --- a/core/primitives/benches/serialization.rs +++ b/core/primitives/benches/serialization.rs @@ -11,7 +11,9 @@ use near_primitives::block::{genesis_chunks, Block}; use near_primitives::hash::CryptoHash; use near_primitives::merkle::combine_hash; use near_primitives::test_utils::account_new; -use near_primitives::transaction::{Action, SignedTransaction, Transaction, TransactionV0, TransferAction}; +use near_primitives::transaction::{ + Action, SignedTransaction, Transaction, TransactionV0, TransferAction, +}; use near_primitives::types::{EpochId, StateRoot}; use near_primitives::validator_signer::InMemoryValidatorSigner; use near_primitives::version::PROTOCOL_VERSION; diff --git a/core/primitives/src/errors.rs b/core/primitives/src/errors.rs index 5e299c9ef91..cd0c4a7d054 100644 --- a/core/primitives/src/errors.rs +++ b/core/primitives/src/errors.rs @@ -176,6 +176,8 @@ pub enum InvalidTxError { ActionsValidation(ActionsValidationError), /// The size of serialized transaction exceeded the limit. TransactionSizeExceeded { size: u64, limit: u64 }, + /// Transaction version is invalid. + InvalidTransactionVersion, } impl std::error::Error for InvalidTxError {} @@ -571,6 +573,9 @@ impl Display for InvalidTxError { InvalidTxError::TransactionSizeExceeded { size, limit } => { write!(f, "Size of serialized transaction {} exceeded the limit {}", size, limit) } + InvalidTxError::InvalidTransactionVersion => { + write!(f, "Transaction version is invalid") + } } } } diff --git a/core/primitives/src/receipt.rs b/core/primitives/src/receipt.rs index 4950bcd9b5b..79a37715374 100644 --- a/core/primitives/src/receipt.rs +++ b/core/primitives/src/receipt.rs @@ -10,7 +10,7 @@ use serde_with::serde_as; use std::borrow::Borrow; use std::collections::HashMap; use std::fmt; -use std::io::{self, BufRead, BufReader, Read}; +use std::io::{self, Read}; use std::io::{Error, ErrorKind}; /// The outgoing (egress) data which will be transformed @@ -104,24 +104,54 @@ impl BorshDeserialize for Receipt { /// No conflict is possible because the first field of Receipt is an `AccountId` which starts /// with a `usize` but can only be at most 64 bytes long, so the highest byte is always 0. fn deserialize_reader(reader: &mut R) -> std::io::Result { - // Note: the following implementation is inefficient because it copies data twice. - // and should be replaced once the protocol switches to the new receipt format entirely. - let mut buf_reader = BufReader::new(reader); - let buffer = buf_reader.fill_buf()?; // Fill the buffer - if buffer.is_empty() { - return Err(Error::new(ErrorKind::UnexpectedEof, "No data to read")); - } else { - let first_byte = buffer[0]; - if first_byte == 0 { - let receipt = ReceiptV0::deserialize_reader(&mut buf_reader)?; - Ok(Receipt::V0(receipt)) - } else if first_byte == 1 { - let _ = buf_reader.consume(1); // Consume the first byte - let receipt = ReceiptV1::deserialize_reader(&mut buf_reader)?; - Ok(Receipt::V1(receipt)) - } else { - Err(Error::new(ErrorKind::InvalidData, "Invalid version")) + let u1 = u8::deserialize_reader(reader)?; + let u2 = u8::deserialize_reader(reader)?; + let u3 = u8::deserialize_reader(reader)?; + let u4 = u8::deserialize_reader(reader)?; + // This is a ridiculous hackery: because the first field in `ReceiptV0` is an `AccountId` + // and an account id is at most 64 bytes, for all valid `ReceiptV0` the second byte must be 0 + // because of the littel endian encoding of the length of the account id. + // On the other hand, for `ReceiptV0`, since the first byte is 1 and an account id must have nonzero + // length, so the second byte must not be zero. Therefore, we can distinguish between the two versions + // by looking at the second byte. + + let read_predecessor_id = |buf: [u8; 4], reader: &mut R| -> std::io::Result { + let str_len = u32::from_le_bytes(buf); + let mut str_vec = Vec::with_capacity(str_len as usize); + for _ in 0..str_len { + str_vec.push(u8::deserialize_reader(reader)?); } + AccountId::try_from(String::from_utf8(str_vec).map_err(|_| { + Error::new(ErrorKind::InvalidData, "Failed to parse AccountId from bytes") + })?) + .map_err(|e| Error::new(ErrorKind::InvalidData, e.to_string())) + }; + + if u2 == 0 { + let signer_id = read_predecessor_id([u1, u2, u3, u4], reader)?; + let receiver_id = AccountId::deserialize_reader(reader)?; + let receipt_id = CryptoHash::deserialize_reader(reader)?; + let receipt = ReceiptEnum::deserialize_reader(reader)?; + Ok(Receipt::V0(ReceiptV0 { + predecessor_id: signer_id, + receiver_id, + receipt_id, + receipt, + })) + } else { + let u5 = u8::deserialize_reader(reader)?; + let signer_id = read_predecessor_id([u2, u3, u4, u5], reader)?; + let receiver_id = AccountId::deserialize_reader(reader)?; + let receipt_id = CryptoHash::deserialize_reader(reader)?; + let receipt = ReceiptEnum::deserialize_reader(reader)?; + let priority = u64::deserialize_reader(reader)?; + Ok(Receipt::V1(ReceiptV1 { + predecessor_id: signer_id, + receiver_id, + receipt_id, + receipt, + priority, + })) } } } @@ -224,7 +254,7 @@ impl Receipt { /// It's not a content hash, but receipt_id is unique. pub fn get_hash(&self) -> CryptoHash { - *self.receipt_id() + *self.receipt_id() } /// Generates a receipt with a transfer from system for a given balance without a receipt_id. @@ -459,3 +489,45 @@ pub struct PromiseYieldTimeout { /// Map of shard to list of receipts to send to it. pub type ReceiptResult = HashMap>; + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_receipt_serialization() { + let receipt_v0 = Receipt::V0(ReceiptV0 { + predecessor_id: "predecessor_id".parse().unwrap(), + receiver_id: "receiver_id".parse().unwrap(), + receipt_id: CryptoHash::default(), + receipt: ReceiptEnum::Action(ActionReceipt { + signer_id: "signer_id".parse().unwrap(), + signer_public_key: PublicKey::empty(KeyType::ED25519), + gas_price: 0, + output_data_receivers: vec![], + input_data_ids: vec![], + actions: vec![Action::Transfer(TransferAction { deposit: 0 })], + }), + }); + let serialized_receipt = borsh::to_vec(&receipt_v0).unwrap(); + let receipt2 = Receipt::try_from_slice(&serialized_receipt).unwrap(); + assert_eq!(receipt_v0, receipt2); + + let receipt_v1 = Receipt::V1(ReceiptV1 { + predecessor_id: "predecessor_id".parse().unwrap(), + receiver_id: "receiver_id".parse().unwrap(), + receipt_id: CryptoHash::default(), + receipt: ReceiptEnum::Action(ActionReceipt { + signer_id: "signer_id".parse().unwrap(), + signer_public_key: PublicKey::empty(KeyType::ED25519), + gas_price: 0, + output_data_receivers: vec![], + input_data_ids: vec![], + actions: vec![Action::Transfer(TransferAction { deposit: 0 })], + }), + priority: 1, + }); + let serialized_receipt = borsh::to_vec(&receipt_v1).unwrap(); + let receipt2 = Receipt::try_from_slice(&serialized_receipt).unwrap(); + assert_eq!(receipt_v1, receipt2); + } +} diff --git a/core/primitives/src/test_utils.rs b/core/primitives/src/test_utils.rs index affa017a3c9..0b01d9738d7 100644 --- a/core/primitives/src/test_utils.rs +++ b/core/primitives/src/test_utils.rs @@ -9,7 +9,9 @@ use crate::merkle::PartialMerkleTree; use crate::num_rational::Ratio; use crate::sharding::{ShardChunkHeader, ShardChunkHeaderV3}; use crate::transaction::{ - Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction, DeployContractAction, FunctionCallAction, SignedTransaction, StakeAction, Transaction, TransactionV1, TransferAction + Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction, + DeployContractAction, FunctionCallAction, SignedTransaction, StakeAction, Transaction, + TransactionV0, TransactionV1, TransferAction, }; use crate::types::{AccountId, Balance, EpochId, EpochInfoProvider, Gas, Nonce}; use crate::validator_signer::{InMemoryValidatorSigner, ValidatorSigner}; @@ -34,9 +36,17 @@ impl Transaction { receiver_id: AccountId, nonce: Nonce, block_hash: CryptoHash, - priority_fee: u64 + priority_fee: u64, ) -> Self { - Transaction::V1(TransactionV1 { signer_id, public_key, nonce, receiver_id, block_hash, actions: vec![], priority_fee }) + Transaction::V1(TransactionV1 { + signer_id, + public_key, + nonce, + receiver_id, + block_hash, + actions: vec![], + priority_fee, + }) } pub fn actions_mut(&mut self) -> &mut Vec { @@ -110,9 +120,31 @@ impl Transaction { } /// This block implements a set of helper functions to create transactions for testing purposes. -/// Therefore, `TransactionV1` is used to create transactions. impl SignedTransaction { + /// Creates v0 for now because v1 is prohibited in the protocol. + /// Once v1 is allowed, this function should be updated to create v1 transactions. pub fn from_actions( + nonce: Nonce, + signer_id: AccountId, + receiver_id: AccountId, + signer: &dyn Signer, + actions: Vec, + block_hash: CryptoHash, + _priority_fee: u64, + ) -> Self { + Transaction::V0(TransactionV0 { + nonce, + signer_id, + public_key: signer.public_key(), + receiver_id, + block_hash, + actions, + }) + .sign(signer) + } + + /// Explicitly create v1 transaction to test in cases where errors are expected. + pub fn from_actions_v1( nonce: Nonce, signer_id: AccountId, receiver_id: AccountId, @@ -128,7 +160,7 @@ impl SignedTransaction { receiver_id, block_hash, actions, - priority_fee + priority_fee, }) .sign(signer) } @@ -148,7 +180,7 @@ impl SignedTransaction { signer, vec![Action::Transfer(TransferAction { deposit })], block_hash, - 0 + 0, ) } @@ -167,7 +199,7 @@ impl SignedTransaction { signer, vec![Action::Stake(Box::new(StakeAction { stake, public_key }))], block_hash, - 0 + 0, ) } @@ -194,7 +226,7 @@ impl SignedTransaction { Action::Transfer(TransferAction { deposit: amount }), ], block_hash, - 0 + 0, ) } @@ -223,7 +255,7 @@ impl SignedTransaction { Action::DeployContract(DeployContractAction { code }), ], block_hash, - 0 + 0, ) } @@ -250,7 +282,7 @@ impl SignedTransaction { deposit, }))], block_hash, - 0 + 0, ) } @@ -269,7 +301,7 @@ impl SignedTransaction { signer, vec![Action::DeleteAccount(DeleteAccountAction { beneficiary_id })], block_hash, - 0 + 0, ) } @@ -281,7 +313,7 @@ impl SignedTransaction { &EmptySigner {}, vec![], block_hash, - 0 + 0, ) } } diff --git a/core/primitives/src/transaction.rs b/core/primitives/src/transaction.rs index 6cfa131c086..ffc26ba5b4d 100644 --- a/core/primitives/src/transaction.rs +++ b/core/primitives/src/transaction.rs @@ -13,7 +13,7 @@ use serde::ser::Error as EncodeError; use std::borrow::Borrow; use std::fmt; use std::hash::{Hash, Hasher}; -use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Write}; +use std::io::{Error, ErrorKind, Read, Write}; #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] pub use crate::action::NonrefundableStorageTransferAction; @@ -151,27 +151,63 @@ impl BorshDeserialize for Transaction { /// Deserialize based on the first byte of the buffer. If the first byte is 0, it is a V0 /// Otherwise, it is a V1. For V0, we do backward compatible deserialization by deserializing /// the entire stream into V0. For V1, we consume the first byte and then deserialize the rest - /// No conflict is possible because the first field of Transaction is an `AccountId` which starts - /// with a `usize` but can only be at most 64 bytes long, so the highest byte is always 0. fn deserialize_reader(reader: &mut R) -> std::io::Result { - // Note: the following implementation is inefficient because it copies data twice. - // and should be replaced once the protocol switches to the new transaction format entirely. - let mut buf_reader = BufReader::new(reader); - let buffer = buf_reader.fill_buf()?; // Fill the buffer - if buffer.is_empty() { - return Err(Error::new(ErrorKind::UnexpectedEof, "No data to read")); - } else { - let first_byte = buffer[0]; - if first_byte == 0 { - let tx = TransactionV0::deserialize_reader(&mut buf_reader)?; - Ok(Transaction::V0(tx)) - } else if first_byte == 1 { - let _ = buf_reader.consume(1); // Consume the first byte - let tx = TransactionV1::deserialize_reader(&mut buf_reader)?; - Ok(Transaction::V1(tx)) - } else { - Err(Error::new(ErrorKind::InvalidData, "Invalid version")) + let u1 = u8::deserialize_reader(reader)?; + let u2 = u8::deserialize_reader(reader)?; + let u3 = u8::deserialize_reader(reader)?; + let u4 = u8::deserialize_reader(reader)?; + // This is a ridiculous hackery: because the first field in `TransactionV0` is an `AccountId` + // and an account id is at most 64 bytes, for all valid `TransactionV0` the second byte must be 0 + // because of the littel endian encoding of the length of the account id. + // On the other hand, for `TransactionV1`, since the first byte is 1 and an account id must have nonzero + // length, so the second byte must not be zero. Therefore, we can distinguish between the two versions + // by looking at the second byte. + + let read_signer_id = |buf: [u8; 4], reader: &mut R| -> std::io::Result { + let str_len = u32::from_le_bytes(buf); + let mut str_vec = Vec::with_capacity(str_len as usize); + for _ in 0..str_len { + str_vec.push(u8::deserialize_reader(reader)?); } + AccountId::try_from(String::from_utf8(str_vec).map_err(|_| { + Error::new(ErrorKind::InvalidData, "Failed to parse AccountId from bytes") + })?) + .map_err(|e| Error::new(ErrorKind::InvalidData, e.to_string())) + }; + + if u2 == 0 { + let signer_id = read_signer_id([u1, u2, u3, u4], reader)?; + let public_key = PublicKey::deserialize_reader(reader)?; + let nonce = Nonce::deserialize_reader(reader)?; + let receiver_id = AccountId::deserialize_reader(reader)?; + let block_hash = CryptoHash::deserialize_reader(reader)?; + let actions = Vec::::deserialize_reader(reader)?; + Ok(Transaction::V0(TransactionV0 { + signer_id, + public_key, + nonce, + receiver_id, + block_hash, + actions, + })) + } else { + let u5 = u8::deserialize_reader(reader)?; + let signer_id = read_signer_id([u2, u3, u4, u5], reader)?; + let public_key = PublicKey::deserialize_reader(reader)?; + let nonce = Nonce::deserialize_reader(reader)?; + let receiver_id = AccountId::deserialize_reader(reader)?; + let block_hash = CryptoHash::deserialize_reader(reader)?; + let actions = Vec::::deserialize_reader(reader)?; + let priority_fee = u64::deserialize_reader(reader)?; + Ok(Transaction::V1(TransactionV1 { + signer_id, + public_key, + nonce, + receiver_id, + block_hash, + actions, + priority_fee, + })) } } } @@ -467,12 +503,50 @@ mod tests { assert!(verify_transaction_signature(&decoded_tx, &valid_keys)); } - /// This test is change checker for a reason - we don't expect transaction format to change. - /// If it does - you MUST update all of the dependencies: like nearlib and other clients. - #[test] - fn test_serialize_transaction() { + fn create_transaction_v0() -> TransactionV0 { let public_key: PublicKey = "22skMptHjFWNyuEWY22ftn2AbLPSYpmYwGJRGwpNHbTV".parse().unwrap(); - let transaction = Transaction::V0(TransactionV0 { + TransactionV0 { + signer_id: "test.near".parse().unwrap(), + public_key: public_key.clone(), + nonce: 1, + receiver_id: "123".parse().unwrap(), + block_hash: Default::default(), + actions: vec![ + Action::CreateAccount(CreateAccountAction {}), + Action::DeployContract(DeployContractAction { code: vec![1, 2, 3] }), + Action::FunctionCall(Box::new(FunctionCallAction { + method_name: "qqq".to_string(), + args: vec![1, 2, 3], + gas: 1_000, + deposit: 1_000_000, + })), + Action::Transfer(TransferAction { deposit: 123 }), + Action::Stake(Box::new(StakeAction { + public_key: public_key.clone(), + stake: 1_000_000, + })), + Action::AddKey(Box::new(AddKeyAction { + public_key: public_key.clone(), + access_key: AccessKey { + nonce: 0, + permission: AccessKeyPermission::FunctionCall(FunctionCallPermission { + allowance: None, + receiver_id: "zzz".parse().unwrap(), + method_names: vec!["www".to_string()], + }), + }, + })), + Action::DeleteKey(Box::new(DeleteKeyAction { public_key })), + Action::DeleteAccount(DeleteAccountAction { + beneficiary_id: "123".parse().unwrap(), + }), + ], + } + } + + fn create_transaction_v1() -> TransactionV1 { + let public_key: PublicKey = "22skMptHjFWNyuEWY22ftn2AbLPSYpmYwGJRGwpNHbTV".parse().unwrap(); + TransactionV1 { signer_id: "test.near".parse().unwrap(), public_key: public_key.clone(), nonce: 1, @@ -508,7 +582,15 @@ mod tests { beneficiary_id: "123".parse().unwrap(), }), ], - }); + priority_fee: 1, + } + } + + /// This test is change checker for a reason - we don't expect transaction format to change. + /// If it does - you MUST update all of the dependencies: like nearlib and other clients. + #[test] + fn test_serialize_transaction() { + let transaction = Transaction::V0(create_transaction_v0()); let signed_tx = SignedTransaction::new(Signature::empty(KeyType::ED25519), transaction); let new_signed_tx = SignedTransaction::try_from_slice(&borsh::to_vec(&signed_tx).unwrap()).unwrap(); @@ -520,7 +602,17 @@ mod tests { } #[test] - fn test_serialize_transaction_versions() {} + fn test_serialize_transaction_versions() { + let transaction_v0 = Transaction::V0(create_transaction_v0()); + let serialized_tx_v0 = borsh::to_vec(&transaction_v0).unwrap(); + let deserialized_tx_v0 = Transaction::try_from_slice(&serialized_tx_v0).unwrap(); + assert_eq!(transaction_v0, deserialized_tx_v0); + + let transaction_v1 = Transaction::V1(create_transaction_v1()); + let serialized_tx_v1 = borsh::to_vec(&transaction_v1).unwrap(); + let deserialized_tx_v1 = Transaction::try_from_slice(&serialized_tx_v1).unwrap(); + assert_eq!(transaction_v1, deserialized_tx_v1); + } #[test] fn test_outcome_to_hashes() { diff --git a/core/store/src/test_utils.rs b/core/store/src/test_utils.rs index 3517e7a0ea1..694f4729331 100644 --- a/core/store/src/test_utils.rs +++ b/core/store/src/test_utils.rs @@ -266,13 +266,18 @@ pub fn gen_receipts(rng: &mut impl Rng, max_size: usize) -> Vec { let accounts = gen_accounts_from_alphabet(rng, 1, max_size, &alphabet); accounts .iter() - .map(|account_id| Receipt::V1(ReceiptV1 { - predecessor_id: account_id.clone(), - receiver_id: account_id.clone(), - receipt_id: CryptoHash::default(), - receipt: ReceiptEnum::Data(DataReceipt { data_id: CryptoHash::default(), data: None }), - priority: 0, - })) + .map(|account_id| { + Receipt::V1(ReceiptV1 { + predecessor_id: account_id.clone(), + receiver_id: account_id.clone(), + receipt_id: CryptoHash::default(), + receipt: ReceiptEnum::Data(DataReceipt { + data_id: CryptoHash::default(), + data: None, + }), + priority: 0, + }) + }) .collect() } diff --git a/integration-tests/src/tests/client/benchmarks.rs b/integration-tests/src/tests/client/benchmarks.rs index 323988754c9..ebd1860a628 100644 --- a/integration-tests/src/tests/client/benchmarks.rs +++ b/integration-tests/src/tests/client/benchmarks.rs @@ -41,7 +41,7 @@ fn benchmark_large_chunk_production_time() { &signer, vec![Action::DeployContract(DeployContractAction { code: vec![92; tx_size] })], last_block_hash, - 0 + 0, ); assert_eq!(env.clients[0].process_tx(tx, false, false), ProcessTxResponse::ValidTx); } diff --git a/integration-tests/src/tests/client/features/account_id_in_function_call_permission.rs b/integration-tests/src/tests/client/features/account_id_in_function_call_permission.rs index 6922b1c7cad..b6f796abf17 100644 --- a/integration-tests/src/tests/client/features/account_id_in_function_call_permission.rs +++ b/integration-tests/src/tests/client/features/account_id_in_function_call_permission.rs @@ -58,8 +58,12 @@ fn test_account_id_in_function_call_permission_upgrade() { // Run the transaction, it should pass as we don't do validation at this protocol version. { let tip = env.clients[0].chain.head().unwrap(); - let signed_transaction = - Transaction::V0(TransactionV0 { nonce: 10, block_hash: tip.last_block_hash, ..tx.clone() }).sign(&signer); + let signed_transaction = Transaction::V0(TransactionV0 { + nonce: 10, + block_hash: tip.last_block_hash, + ..tx.clone() + }) + .sign(&signer); assert_eq!( env.clients[0].process_tx(signed_transaction, false, false), ProcessTxResponse::ValidTx @@ -75,7 +79,8 @@ fn test_account_id_in_function_call_permission_upgrade() { { let tip = env.clients[0].chain.head().unwrap(); let signed_transaction = - Transaction::V0(TransactionV0 { nonce: 11, block_hash: tip.last_block_hash, ..tx }).sign(&signer); + Transaction::V0(TransactionV0 { nonce: 11, block_hash: tip.last_block_hash, ..tx }) + .sign(&signer); assert_eq!( env.clients[0].process_tx(signed_transaction, false, false), ProcessTxResponse::InvalidTx(InvalidTxError::ActionsValidation( diff --git a/integration-tests/src/tests/client/features/chunk_nodes_cache.rs b/integration-tests/src/tests/client/features/chunk_nodes_cache.rs index ffbefbf5338..274e3e06a72 100644 --- a/integration-tests/src/tests/client/features/chunk_nodes_cache.rs +++ b/integration-tests/src/tests/client/features/chunk_nodes_cache.rs @@ -51,7 +51,7 @@ fn process_transaction( })), ], last_block_hash, - 0 + 0, ); let tx_hash = tx.get_hash(); assert_eq!(env.clients[0].process_tx(tx, false, false), ProcessTxResponse::ValidTx); diff --git a/integration-tests/src/tests/client/features/flat_storage.rs b/integration-tests/src/tests/client/features/flat_storage.rs index 7a82285b737..e27c41c043c 100644 --- a/integration-tests/src/tests/client/features/flat_storage.rs +++ b/integration-tests/src/tests/client/features/flat_storage.rs @@ -5,7 +5,9 @@ use near_client::ProcessTxResponse; use near_crypto::{InMemorySigner, KeyType, Signer}; use near_parameters::ExtCosts; use near_primitives::test_utils::encode; -use near_primitives::transaction::{Action, ExecutionMetadata, FunctionCallAction, Transaction, TransactionV0}; +use near_primitives::transaction::{ + Action, ExecutionMetadata, FunctionCallAction, Transaction, TransactionV0, +}; use near_primitives::version::ProtocolFeature; use near_primitives_core::hash::CryptoHash; use near_primitives_core::types::Gas; diff --git a/integration-tests/src/tests/client/features/increase_storage_compute_cost.rs b/integration-tests/src/tests/client/features/increase_storage_compute_cost.rs index 33fc68b2aff..7b4c18555ab 100644 --- a/integration-tests/src/tests/client/features/increase_storage_compute_cost.rs +++ b/integration-tests/src/tests/client/features/increase_storage_compute_cost.rs @@ -313,7 +313,7 @@ fn produce_saturated_chunk( &signer, actions.clone(), tip.last_block_hash, - 0 + 0, ); *nonce += 1; tx diff --git a/integration-tests/src/tests/client/features/lower_storage_key_limit.rs b/integration-tests/src/tests/client/features/lower_storage_key_limit.rs index 2c3a847dc2e..f56932cf0d3 100644 --- a/integration-tests/src/tests/client/features/lower_storage_key_limit.rs +++ b/integration-tests/src/tests/client/features/lower_storage_key_limit.rs @@ -79,9 +79,12 @@ fn protocol_upgrade() { // Run transaction writing storage key exceeding the limit. Check that execution succeeds. { let tip = env.clients[0].chain.head().unwrap(); - let signed_tx = - Transaction::V0(TransactionV0 { nonce: tip.height + 1, block_hash: tip.last_block_hash, ..tx.clone() }) - .sign(&signer); + let signed_tx = Transaction::V0(TransactionV0 { + nonce: tip.height + 1, + block_hash: tip.last_block_hash, + ..tx.clone() + }) + .sign(&signer); let tx_hash = signed_tx.get_hash(); assert_eq!(env.clients[0].process_tx(signed_tx, false, false), ProcessTxResponse::ValidTx); produce_blocks_from_height_with_protocol_version( @@ -99,9 +102,12 @@ fn protocol_upgrade() { // Re-run the transaction, check that execution fails. { let tip = env.clients[0].chain.head().unwrap(); - let signed_tx = - Transaction::V0(TransactionV0 { nonce: tip.height + 1, block_hash: tip.last_block_hash, ..tx }) - .sign(&signer); + let signed_tx = Transaction::V0(TransactionV0 { + nonce: tip.height + 1, + block_hash: tip.last_block_hash, + ..tx + }) + .sign(&signer); let tx_hash = signed_tx.get_hash(); assert_eq!(env.clients[0].process_tx(signed_tx, false, false), ProcessTxResponse::ValidTx); for i in 0..epoch_length { @@ -136,9 +142,12 @@ fn protocol_upgrade() { block_hash: CryptoHash::default(), }; let tip = env.clients[0].chain.head().unwrap(); - let signed_tx = - Transaction::V0(TransactionV0 { nonce: tip.height + 1, block_hash: tip.last_block_hash, ..tx }) - .sign(&signer); + let signed_tx = Transaction::V0(TransactionV0 { + nonce: tip.height + 1, + block_hash: tip.last_block_hash, + ..tx + }) + .sign(&signer); let tx_hash = signed_tx.get_hash(); assert_eq!(env.clients[0].process_tx(signed_tx, false, false), ProcessTxResponse::ValidTx); for i in 0..epoch_length { diff --git a/integration-tests/src/tests/client/features/nearvm.rs b/integration-tests/src/tests/client/features/nearvm.rs index 332f7684585..f1b56bbb77a 100644 --- a/integration-tests/src/tests/client/features/nearvm.rs +++ b/integration-tests/src/tests/client/features/nearvm.rs @@ -61,8 +61,12 @@ fn test_nearvm_upgrade() { // Run the transaction & collect the logs. let logs_at_old_version = { let tip = env.clients[0].chain.head().unwrap(); - let signed_transaction = - Transaction::V0(TransactionV0 { nonce: 10, block_hash: tip.last_block_hash, ..tx.clone() }).sign(&signer); + let signed_transaction = Transaction::V0(TransactionV0 { + nonce: 10, + block_hash: tip.last_block_hash, + ..tx.clone() + }) + .sign(&signer); assert_eq!( env.clients[0].process_tx(signed_transaction, false, false), ProcessTxResponse::ValidTx @@ -79,7 +83,8 @@ fn test_nearvm_upgrade() { let logs_at_new_version = { let tip = env.clients[0].chain.head().unwrap(); let signed_transaction = - Transaction::V0(TransactionV0 { nonce: 11, block_hash: tip.last_block_hash, ..tx }).sign(&signer); + Transaction::V0(TransactionV0 { nonce: 11, block_hash: tip.last_block_hash, ..tx }) + .sign(&signer); assert_eq!( env.clients[0].process_tx(signed_transaction, false, false), ProcessTxResponse::ValidTx diff --git a/integration-tests/src/tests/client/features/storage_proof_size_limit.rs b/integration-tests/src/tests/client/features/storage_proof_size_limit.rs index cf08dde996b..294e8ab9e5c 100644 --- a/integration-tests/src/tests/client/features/storage_proof_size_limit.rs +++ b/integration-tests/src/tests/client/features/storage_proof_size_limit.rs @@ -74,7 +74,7 @@ fn test_storage_proof_size_limit() { &signer, vec![action], env.clients[0].chain.head().unwrap().last_block_hash, - 0 + 0, ); nonce += 1; let res = env.execute_tx(tx).unwrap(); @@ -97,7 +97,7 @@ fn test_storage_proof_size_limit() { &signer, vec![action], after_writes_block_hash, - 0 + 0, ); nonce += 1; tx diff --git a/integration-tests/src/tests/client/features/wallet_contract.rs b/integration-tests/src/tests/client/features/wallet_contract.rs index 72ff960c6c5..da5f7a605a6 100644 --- a/integration-tests/src/tests/client/features/wallet_contract.rs +++ b/integration-tests/src/tests/client/features/wallet_contract.rs @@ -212,7 +212,7 @@ fn test_transaction_from_eth_implicit_account_fail() { access_key: AccessKey::full_access(), }))], *block.hash(), - 0 + 0, ); let response = env.clients[0].process_tx(add_access_key_to_eth_implicit_account_tx, false, false); @@ -227,7 +227,7 @@ fn test_transaction_from_eth_implicit_account_fail() { ð_implicit_account_signer, vec![Action::DeployContract(DeployContractAction { code: wallet_contract_code })], *block.hash(), - 0 + 0, ); let response = env.clients[0].process_tx(add_access_key_to_eth_implicit_account_tx, false, false); @@ -275,7 +275,7 @@ fn test_wallet_contract_interaction() { &relayer_signer.signer, actions, block_hash, - 0 + 0, ); height = check_tx_processing(&mut env, signed_transaction, height, blocks_number); @@ -398,7 +398,7 @@ fn create_rlp_execute_tx( &near_signer.signer, actions, block_hash, - 0 + 0, ) } diff --git a/integration-tests/src/tests/client/features/zero_balance_account.rs b/integration-tests/src/tests/client/features/zero_balance_account.rs index 0d265cc9ce1..432dab19d4d 100644 --- a/integration-tests/src/tests/client/features/zero_balance_account.rs +++ b/integration-tests/src/tests/client/features/zero_balance_account.rs @@ -192,7 +192,7 @@ fn test_zero_balance_account_add_key() { &new_signer, actions, *genesis_block.hash(), - 0 + 0, ); assert_eq!(env.clients[0].process_tx(add_key_tx, false, false), ProcessTxResponse::ValidTx); for i in 5..10 { @@ -223,7 +223,7 @@ fn test_zero_balance_account_add_key() { public_key: keys.last().unwrap().clone(), }))], *genesis_block.hash(), - 0 + 0, ); assert_eq!(env.clients[0].process_tx(delete_key_tx, false, false), ProcessTxResponse::ValidTx); for i in 10..15 { diff --git a/integration-tests/src/tests/client/process_blocks.rs b/integration-tests/src/tests/client/process_blocks.rs index 608bf38f6ef..e45e5fca043 100644 --- a/integration-tests/src/tests/client/process_blocks.rs +++ b/integration-tests/src/tests/client/process_blocks.rs @@ -163,7 +163,7 @@ pub(crate) fn deploy_test_contract_with_protocol_version( &signer, vec![Action::DeployContract(DeployContractAction { code: wasm_code.to_vec() })], *block.hash(), - 0 + 0, ); assert_eq!(env.clients[0].process_tx(tx, false, false), ProcessTxResponse::ValidTx); produce_blocks_from_height_with_protocol_version(env, epoch_length, height, protocol_version) @@ -215,7 +215,7 @@ pub(crate) fn prepare_env_with_congestion( code: near_test_contracts::backwards_compatible_rs_contract().to_vec(), })], *genesis_block.hash(), - 0 + 0, ); assert_eq!(env.clients[0].process_tx(tx, false, false), ProcessTxResponse::ValidTx); for i in 1..3 { @@ -250,7 +250,7 @@ pub(crate) fn prepare_env_with_congestion( deposit: 0, }))], *genesis_block.hash(), - 0 + 0, ); tx_hashes.push(signed_transaction.get_hash()); assert_eq!( @@ -2195,7 +2195,7 @@ fn test_validate_chunk_extra() { code: near_test_contracts::rs_contract().to_vec(), })], *genesis_block.hash(), - 0 + 0, ); assert_eq!(env.clients[0].process_tx(tx, false, false), ProcessTxResponse::ValidTx); let mut last_block = genesis_block; @@ -2218,7 +2218,7 @@ fn test_validate_chunk_extra() { deposit: 0, }))], *last_block.hash(), - 0 + 0, ); assert_eq!( env.clients[0].process_tx(function_call_tx, false, false), @@ -2620,7 +2620,7 @@ fn test_delayed_receipt_count_limit() { &signer, vec![Action::DeployContract(DeployContractAction { code: vec![92; 10000] })], *genesis_block.hash(), - 0 + 0, ); assert_eq!(env.clients[0].process_tx(tx, false, false), ProcessTxResponse::ValidTx); } @@ -3298,7 +3298,7 @@ fn test_validator_stake_host_function() { deposit: 0, }))], *genesis_block.hash(), - 0 + 0, ); assert_eq!( env.clients[0].process_tx(signed_transaction, false, false), diff --git a/integration-tests/src/tests/client/resharding.rs b/integration-tests/src/tests/client/resharding.rs index a4b2b5f6cb2..15a125504cd 100644 --- a/integration-tests/src/tests/client/resharding.rs +++ b/integration-tests/src/tests/client/resharding.rs @@ -816,7 +816,8 @@ fn check_outgoing_receipts_reassigned_impl( // In V0->V1 resharding the outgoing receipts should be reassigned // to the receipt receiver's shard id. for receipt in outgoing_receipts { - let receiver_shard_id = account_id_to_shard_id(receipt.receiver_id(), &shard_layout); + let receiver_shard_id = + account_id_to_shard_id(receipt.receiver_id(), &shard_layout); assert_eq!(receiver_shard_id, shard_id); } } @@ -1275,7 +1276,7 @@ fn setup_test_env_with_cross_contract_txs( &signer, actions, genesis_hash, - 0 + 0, ); init_txs.push(tx); } @@ -1449,7 +1450,7 @@ fn gen_cross_contract_tx_impl( deposit: 0, }))], *block_hash, - 0 + 0, ) } diff --git a/integration-tests/src/tests/runtime/deployment.rs b/integration-tests/src/tests/runtime/deployment.rs index fa94b70ec1b..1d036325063 100644 --- a/integration-tests/src/tests/runtime/deployment.rs +++ b/integration-tests/src/tests/runtime/deployment.rs @@ -30,7 +30,7 @@ fn test_deploy_max_size_contract() { &*node_user.signer(), vec![Action::DeployContract(DeployContractAction { code: vec![0u8] })], block_hash, - 0 + 0, ); let tx_overhead = signed_transaction.get_size(); diff --git a/integration-tests/src/tests/test_errors.rs b/integration-tests/src/tests/test_errors.rs index b1121975378..9fbd1d67f8a 100644 --- a/integration-tests/src/tests/test_errors.rs +++ b/integration-tests/src/tests/test_errors.rs @@ -49,7 +49,7 @@ fn test_check_tx_error_log() { })), ], block_hash, - 0 + 0, ); let tx_result = node.user().commit_transaction(tx).unwrap_err(); @@ -90,7 +90,7 @@ fn test_deliver_tx_error_log() { })), ], block_hash, - 0 + 0, ); let tx_result = node.user().commit_transaction(tx).unwrap_err(); diff --git a/integration-tests/src/user/mod.rs b/integration-tests/src/user/mod.rs index db8df92396d..e489aa4887d 100644 --- a/integration-tests/src/user/mod.rs +++ b/integration-tests/src/user/mod.rs @@ -106,7 +106,7 @@ pub trait User { &*self.signer(), actions, block_hash, - 0 + 0, ); self.commit_transaction(signed_transaction) } diff --git a/runtime/runtime-params-estimator/src/transaction_builder.rs b/runtime/runtime-params-estimator/src/transaction_builder.rs index 9617e934d11..412fea0d5cd 100644 --- a/runtime/runtime-params-estimator/src/transaction_builder.rs +++ b/runtime/runtime-params-estimator/src/transaction_builder.rs @@ -62,7 +62,7 @@ impl TransactionBuilder { &signer, actions, CryptoHash::default(), - 0 + 0, ) } diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index 198b4cfcc26..f440121d3c0 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -14,7 +14,9 @@ use near_primitives::checked_feature; use near_primitives::config::ViewConfig; use near_primitives::errors::{ActionError, ActionErrorKind, InvalidAccessKeyError, RuntimeError}; use near_primitives::hash::CryptoHash; -use near_primitives::receipt::{ActionReceipt, DataReceipt, Receipt, ReceiptEnum, ReceiptPriority, ReceiptV0}; +use near_primitives::receipt::{ + ActionReceipt, DataReceipt, Receipt, ReceiptEnum, ReceiptPriority, ReceiptV0, +}; use near_primitives::transaction::{ Action, AddKeyAction, DeleteAccountAction, DeleteKeyAction, DeployContractAction, FunctionCallAction, StakeAction, @@ -1298,7 +1300,11 @@ mod tests { Some(Account::new(100, 0, 0, *code_hash, storage_usage, PROTOCOL_VERSION)); let mut actor_id = account_id.clone(); let mut action_result = ActionResult::default(); - let receipt = Receipt::new_balance_refund(&"alice.near".parse().unwrap(), 0, ReceiptPriority::NoPriority); + let receipt = Receipt::new_balance_refund( + &"alice.near".parse().unwrap(), + 0, + ReceiptPriority::NoPriority, + ); let res = action_delete_account( state_update, &mut account, @@ -1469,7 +1475,7 @@ mod tests { &sender_id, &signed_delegate_action, &mut result, - ReceiptPriority::NoPriority + ReceiptPriority::NoPriority, ) .expect("Expect ok"); @@ -1514,7 +1520,7 @@ mod tests { &sender_id, &signed_delegate_action, &mut result, - ReceiptPriority::NoPriority + ReceiptPriority::NoPriority, ) .expect("Expect ok"); @@ -1541,7 +1547,7 @@ mod tests { &sender_id, &signed_delegate_action, &mut result, - ReceiptPriority::NoPriority + ReceiptPriority::NoPriority, ) .expect("Expect ok"); @@ -1568,7 +1574,7 @@ mod tests { &"www.test.near".parse().unwrap(), &signed_delegate_action, &mut result, - ReceiptPriority::NoPriority + ReceiptPriority::NoPriority, ) .expect("Expect ok"); diff --git a/runtime/runtime/src/balance_checker.rs b/runtime/runtime/src/balance_checker.rs index c81241e1e42..5fcdb293cd6 100644 --- a/runtime/runtime/src/balance_checker.rs +++ b/runtime/runtime/src/balance_checker.rs @@ -45,7 +45,11 @@ fn receipt_cost( if !receipt.predecessor_id().is_system() { let mut total_gas = safe_add_gas( config.fees.fee(ActionCosts::new_action_receipt).exec_fee(), - total_prepaid_exec_fees(config, &action_receipt.actions, receipt.receiver_id())?, + total_prepaid_exec_fees( + config, + &action_receipt.actions, + receipt.receiver_id(), + )?, )?; total_gas = safe_add_gas(total_gas, total_prepaid_gas(&action_receipt.actions)?)?; total_gas = safe_add_gas( @@ -204,9 +208,11 @@ pub(crate) fn check_balance( .filter_map(|receipt| { let account_id = receipt.receiver_id(); match receipt.receipt() { - ReceiptEnum::Action(_) => { - Some(Ok((PostponedReceiptType::Action, account_id.clone(), *receipt.receipt_id()))) - } + ReceiptEnum::Action(_) => Some(Ok(( + PostponedReceiptType::Action, + account_id.clone(), + *receipt.receipt_id(), + ))), ReceiptEnum::Data(data_receipt) => { let result = get( initial_state, @@ -392,7 +398,11 @@ mod tests { &RuntimeConfig::test(), &final_state, &None, - &[Receipt::new_balance_refund(&account_id, refund_balance, ReceiptPriority::NoPriority)], + &[Receipt::new_balance_refund( + &account_id, + refund_balance, + ReceiptPriority::NoPriority, + )], &[], &[], &[], diff --git a/runtime/runtime/src/config.rs b/runtime/runtime/src/config.rs index 80c8a735588..a833af19697 100644 --- a/runtime/runtime/src/config.rs +++ b/runtime/runtime/src/config.rs @@ -305,13 +305,7 @@ pub fn tx_cost( let remaining_gas_amount = safe_gas_to_balance(receipt_gas_price, gas_remaining)?; let mut total_cost = safe_add_balance(burnt_amount, remaining_gas_amount)?; total_cost = safe_add_balance(total_cost, total_deposit(&transaction.actions())?)?; - Ok(TransactionCost { - gas_burnt, - gas_remaining, - receipt_gas_price, - total_cost, - burnt_amount, - }) + Ok(TransactionCost { gas_burnt, gas_remaining, receipt_gas_price, total_cost, burnt_amount }) } /// Total sum of gas that would need to be burnt before we start executing the given actions. diff --git a/runtime/runtime/src/lib.rs b/runtime/runtime/src/lib.rs index 877fe74c036..7ab493687e7 100644 --- a/runtime/runtime/src/lib.rs +++ b/runtime/runtime/src/lib.rs @@ -20,7 +20,8 @@ use near_primitives::errors::{ }; use near_primitives::hash::CryptoHash; use near_primitives::receipt::{ - ActionReceipt, DataReceipt, DelayedReceiptIndices, PromiseYieldIndices, PromiseYieldTimeout, Receipt, ReceiptEnum, ReceiptV0, ReceivedData + ActionReceipt, DataReceipt, DelayedReceiptIndices, PromiseYieldIndices, PromiseYieldTimeout, + Receipt, ReceiptEnum, ReceiptV0, ReceivedData, }; use near_primitives::runtime::migration_data::{MigrationData, MigrationFlags}; use near_primitives::sandbox::state_patch::SandboxStatePatch; @@ -503,7 +504,7 @@ impl Runtime { account_id, signed_delegate_action, &mut result, - receipt.priority() + receipt.priority(), )?; } }; @@ -705,7 +706,8 @@ impl Runtime { } // If the receipt is a refund, then we consider it free without burnt gas. - let gas_burnt: Gas = if receipt.predecessor_id().is_system() { 0 } else { result.gas_burnt }; + let gas_burnt: Gas = + if receipt.predecessor_id().is_system() { 0 } else { result.gas_burnt }; // `gas_deficit_amount` is strictly less than `gas_price * gas_burnt`. let mut tx_burnt_amount = safe_gas_to_balance(apply_state.gas_price, gas_burnt)? - gas_deficit_amount; @@ -766,15 +768,17 @@ impl Runtime { Err(_) => None, }; result.new_receipts.extend(action_receipt.output_data_receivers.iter().map( - |data_receiver| Receipt::V0(ReceiptV0 { - predecessor_id: account_id.clone(), - receiver_id: data_receiver.receiver_id.clone(), - receipt_id: CryptoHash::default(), - receipt: ReceiptEnum::Data(DataReceipt { - data_id: data_receiver.data_id, - data: data.clone(), - }), - }), + |data_receiver| { + Receipt::V0(ReceiptV0 { + predecessor_id: account_id.clone(), + receiver_id: data_receiver.receiver_id.clone(), + receipt_id: CryptoHash::default(), + receipt: ReceiptEnum::Data(DataReceipt { + data_id: data_receiver.data_id, + data: data.clone(), + }), + }) + }, )); }; } @@ -2035,7 +2039,11 @@ mod tests { tries.get_trie_for_shard(ShardUId::single_shard(), root), &Some(validator_accounts_update), &apply_state, - &[Receipt::new_balance_refund(&alice_account(), small_refund, ReceiptPriority::NoPriority)], + &[Receipt::new_balance_refund( + &alice_account(), + small_refund, + ReceiptPriority::NoPriority, + )], &[], &epoch_info_provider, Default::default(), @@ -2282,7 +2290,11 @@ mod tests { (0..n) .map(|i| { receipt_id = hash(receipt_id.as_ref()); - Receipt::new_balance_refund(&alice_account(), small_transfer + Balance::from(i), ReceiptPriority::NoPriority) + Receipt::new_balance_refund( + &alice_account(), + small_transfer + Balance::from(i), + ReceiptPriority::NoPriority, + ) }) .collect() } @@ -2411,7 +2423,7 @@ mod tests { &apply_state.prev_block_hash, &apply_state.block_hash, ), // receipt for tx 3 - *receipts[0].receipt_id(), // receipt #0 + *receipts[0].receipt_id(), // receipt #0 ], "STEP #2 failed", ); diff --git a/runtime/runtime/src/verifier.rs b/runtime/runtime/src/verifier.rs index 46594af3f22..14c1c9e4029 100644 --- a/runtime/runtime/src/verifier.rs +++ b/runtime/runtime/src/verifier.rs @@ -98,6 +98,10 @@ pub fn validate_transaction( verify_signature: bool, current_protocol_version: ProtocolVersion, ) -> Result { + // Don't allow V1 currently. This will be changed when the new protocol version is introduced. + if matches!(signed_transaction.transaction, near_primitives::transaction::Transaction::V1(_)) { + return Err(InvalidTxError::InvalidTransactionVersion.into()); + } let transaction = &signed_transaction.transaction; let signer_id = transaction.signer_id(); @@ -143,7 +147,7 @@ pub fn verify_and_charge_transaction( block_height: Option, current_protocol_version: ProtocolVersion, ) -> Result { - let TransactionCost { gas_burnt, gas_remaining, receipt_gas_price, total_cost, burnt_amount, } = + let TransactionCost { gas_burnt, gas_remaining, receipt_gas_price, total_cost, burnt_amount } = validate_transaction( config, gas_price, @@ -962,7 +966,7 @@ mod tests { deposit: 0, }))], CryptoHash::default(), - 0 + 0, ), RuntimeError::InvalidTxError(InvalidTxError::ActionsValidation( ActionsValidationError::TotalPrepaidGasExceeded { @@ -1056,6 +1060,29 @@ mod tests { ); } + #[test] + fn test_validate_transaction_invalid_transaction_version() { + let config = RuntimeConfig::test(); + let (signer, mut state_update, gas_price) = + setup_common(TESTING_INIT_BALANCE, 0, Some(AccessKey::full_access())); + + assert_err_both_validations( + &config, + &mut state_update, + gas_price, + &SignedTransaction::from_actions_v1( + 1, + alice_account(), + bob_account(), + &*signer, + vec![Action::Transfer(TransferAction { deposit: 100 })], + CryptoHash::default(), + 1, + ), + RuntimeError::InvalidTxError(InvalidTxError::InvalidTransactionVersion), + ); + } + #[test] fn test_validate_transaction_invalid_not_enough_balance() { let config = RuntimeConfig::test(); @@ -1125,7 +1152,7 @@ mod tests { deposit: 0, }))], CryptoHash::default(), - 0 + 0, ), true, None, @@ -1475,7 +1502,7 @@ mod tests { &*signer, vec![Action::DeployContract(DeployContractAction { code: vec![1; 5] })], CryptoHash::default(), - 0 + 0, ); let transaction_size = transaction.get_size(); diff --git a/runtime/runtime/tests/runtime_group_tools/mod.rs b/runtime/runtime/tests/runtime_group_tools/mod.rs index 4ad7b9fd72b..e83e6cb5d0c 100644 --- a/runtime/runtime/tests/runtime_group_tools/mod.rs +++ b/runtime/runtime/tests/runtime_group_tools/mod.rs @@ -323,7 +323,8 @@ impl RuntimeGroup { mailbox.incoming_transactions.clear(); group.transaction_logs.lock().unwrap().extend(transaction_results); for new_receipt in new_receipts { - let locked_other_mailbox = mailboxes.get_mut(new_receipt.receiver_id()).unwrap(); + let locked_other_mailbox = + mailboxes.get_mut(new_receipt.receiver_id()).unwrap(); locked_other_mailbox.incoming_receipts.push(new_receipt); } group.mailboxes.1.notify_all(); diff --git a/runtime/runtime/tests/test_async_calls.rs b/runtime/runtime/tests/test_async_calls.rs index 0d8188df758..d849cefd239 100644 --- a/runtime/runtime/tests/test_async_calls.rs +++ b/runtime/runtime/tests/test_async_calls.rs @@ -37,7 +37,7 @@ fn test_simple_func_call() { deposit: 0, }))], CryptoHash::default(), - 0 + 0, ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -84,7 +84,7 @@ fn test_single_promise_no_callback() { deposit: 0, }))], CryptoHash::default(), - 0 + 0, ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -151,7 +151,7 @@ fn test_single_promise_with_callback() { deposit: 0, }))], CryptoHash::default(), - 0 + 0, ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -236,7 +236,7 @@ fn test_two_promises_no_callbacks() { deposit: 0, }))], CryptoHash::default(), - 0 + 0, ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -331,7 +331,7 @@ fn test_two_promises_with_two_callbacks() { deposit: 0, }))], CryptoHash::default(), - 0 + 0, ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -496,7 +496,7 @@ fn test_single_promise_with_callback_batch() { deposit: 0, }))], CryptoHash::default(), - 0 + 0, ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -571,7 +571,7 @@ fn test_simple_transfer() { deposit: 0, }))], CryptoHash::default(), - 0 + 0, ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -639,7 +639,7 @@ fn test_create_account_with_transfer_and_full_key() { deposit: 0, }))], CryptoHash::default(), - 0 + 0, ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -752,7 +752,7 @@ fn test_account_factory() { deposit: 0, }))], CryptoHash::default(), - 0 + 0, ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -899,7 +899,7 @@ fn test_create_account_add_key_call_delete_key_delete_account() { deposit: 0, }))], CryptoHash::default(), - 0 + 0, ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); @@ -1061,7 +1061,7 @@ fn test_create_transfer_64len_hex_fail() { deposit: 0, }))], CryptoHash::default(), - 0 + 0, ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); diff --git a/test-utils/runtime-tester/src/run_test.rs b/test-utils/runtime-tester/src/run_test.rs index e19b3012471..56540ba0b06 100644 --- a/test-utils/runtime-tester/src/run_test.rs +++ b/test-utils/runtime-tester/src/run_test.rs @@ -185,7 +185,7 @@ impl TransactionConfig { &self.signer, self.actions.clone(), *last_block.hash(), - 0 + 0, ) } } diff --git a/tools/mirror/src/chain_tracker.rs b/tools/mirror/src/chain_tracker.rs index eecbd84c7d5..e88f1c178f1 100644 --- a/tools/mirror/src/chain_tracker.rs +++ b/tools/mirror/src/chain_tracker.rs @@ -477,8 +477,10 @@ impl TxTracker { for c in self.queued_blocks[0].chunks.iter_mut() { for tx in c.txs.iter_mut() { if let TargetChainTx::AwaitingNonce(t) = tx { - needed_access_keys - .insert((t.target_tx.signer_id().clone(), t.target_tx.public_key().clone())); + needed_access_keys.insert(( + t.target_tx.signer_id().clone(), + t.target_tx.public_key().clone(), + )); } } } diff --git a/tools/mirror/src/lib.rs b/tools/mirror/src/lib.rs index 0c98ebd012b..3444f50b34f 100644 --- a/tools/mirror/src/lib.rs +++ b/tools/mirror/src/lib.rs @@ -586,8 +586,14 @@ impl TxAwaitingNonce { provenance: MappedTxProvenance, nonce_updates: HashSet<(AccountId, PublicKey)>, ) -> Self { - let mut target_tx = - Transaction::new(target_signer_id, target_public_key, target_receiver_id, 0, *ref_hash, 0); + let mut target_tx = Transaction::new( + target_signer_id, + target_public_key, + target_receiver_id, + 0, + *ref_hash, + 0, + ); *target_tx.actions_mut() = actions; Self { source_signer_id, @@ -634,7 +640,7 @@ impl MappedTx { target_receiver_id, nonce, *ref_hash, - 0 + 0, ); *target_tx.actions_mut() = actions; let target_tx = SignedTransaction::new( @@ -1301,7 +1307,8 @@ impl TxMirror { }; if let ReceiptEnum::Action(r) | ReceiptEnum::PromiseYield(r) = receipt.receipt() { - if (provenance.is_create_account() && receipt.predecessor_id() == receipt.receiver_id()) + if (provenance.is_create_account() + && receipt.predecessor_id() == receipt.receiver_id()) || (!provenance.is_create_account() && receipt.predecessor_id() != receipt.receiver_id()) { diff --git a/tools/state-viewer/src/state_dump.rs b/tools/state-viewer/src/state_dump.rs index 5caddf4203a..549d73d2846 100644 --- a/tools/state-viewer/src/state_dump.rs +++ b/tools/state-viewer/src/state_dump.rs @@ -458,7 +458,7 @@ mod test { code: near_test_contracts::backwards_compatible_rs_contract().to_vec(), })], genesis_hash, - 0 + 0, ); let tx01 = SignedTransaction::stake( 1, From 3f08e763f5ba667dc6c62ca282acfb705b3d88ba Mon Sep 17 00:00:00 2001 From: Bowen Wang Date: Fri, 3 May 2024 10:23:11 -0700 Subject: [PATCH 3/8] fix comments --- core/primitives/src/receipt.rs | 7 ++----- core/primitives/src/transaction.rs | 5 ++--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/core/primitives/src/receipt.rs b/core/primitives/src/receipt.rs index 79a37715374..25465593bdb 100644 --- a/core/primitives/src/receipt.rs +++ b/core/primitives/src/receipt.rs @@ -98,11 +98,8 @@ impl BorshSerialize for Receipt { } impl BorshDeserialize for Receipt { - /// Deserialize based on the first byte of the buffer. If the first byte is 0, it is a V0 - /// Otherwise, it is a V1. For V0, we do backward compatible deserialization by deserializing - /// the entire stream into V0. For V1, we consume the first byte and then deserialize the rest - /// No conflict is possible because the first field of Receipt is an `AccountId` which starts - /// with a `usize` but can only be at most 64 bytes long, so the highest byte is always 0. + /// Deserialize based on the first and second bytes of the stream. For V0, we do backward compatible deserialization by deserializing + /// the entire stream into V0. For V1, we consume the first byte and then deserialize the rest. fn deserialize_reader(reader: &mut R) -> std::io::Result { let u1 = u8::deserialize_reader(reader)?; let u2 = u8::deserialize_reader(reader)?; diff --git a/core/primitives/src/transaction.rs b/core/primitives/src/transaction.rs index ffc26ba5b4d..c0a1b15c13f 100644 --- a/core/primitives/src/transaction.rs +++ b/core/primitives/src/transaction.rs @@ -148,9 +148,8 @@ impl BorshSerialize for Transaction { } impl BorshDeserialize for Transaction { - /// Deserialize based on the first byte of the buffer. If the first byte is 0, it is a V0 - /// Otherwise, it is a V1. For V0, we do backward compatible deserialization by deserializing - /// the entire stream into V0. For V1, we consume the first byte and then deserialize the rest + /// Deserialize based on the first and second bytes of the stream. For V0, we do backward compatible deserialization by deserializing + /// the entire stream into V0. For V1, we consume the first byte and then deserialize the rest. fn deserialize_reader(reader: &mut R) -> std::io::Result { let u1 = u8::deserialize_reader(reader)?; let u2 = u8::deserialize_reader(reader)?; From 37d6a454acdecc54338e227498ab58d685636800 Mon Sep 17 00:00:00 2001 From: Bowen Wang Date: Mon, 13 May 2024 11:21:11 -0700 Subject: [PATCH 4/8] address comments --- core/primitives/src/receipt.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/primitives/src/receipt.rs b/core/primitives/src/receipt.rs index 25465593bdb..d5aeaf84c15 100644 --- a/core/primitives/src/receipt.rs +++ b/core/primitives/src/receipt.rs @@ -490,8 +490,9 @@ pub type ReceiptResult = HashMap>; #[cfg(test)] mod tests { use super::*; + #[test] - fn test_receipt_serialization() { + fn test_receipt_v0_serialization() { let receipt_v0 = Receipt::V0(ReceiptV0 { predecessor_id: "predecessor_id".parse().unwrap(), receiver_id: "receiver_id".parse().unwrap(), @@ -508,7 +509,10 @@ mod tests { let serialized_receipt = borsh::to_vec(&receipt_v0).unwrap(); let receipt2 = Receipt::try_from_slice(&serialized_receipt).unwrap(); assert_eq!(receipt_v0, receipt2); + } + #[test] + fn test_receipt_v1_serialization() { let receipt_v1 = Receipt::V1(ReceiptV1 { predecessor_id: "predecessor_id".parse().unwrap(), receiver_id: "receiver_id".parse().unwrap(), From 7ce7eb08562b9b5196b62b4553f5a9bff0915877 Mon Sep 17 00:00:00 2001 From: Bowen Wang Date: Mon, 13 May 2024 16:06:43 -0700 Subject: [PATCH 5/8] fix --- chain/chain/src/runtime/mod.rs | 2 +- .../src/tests/client/features/yield_timeouts.rs | 8 ++++++-- runtime/runtime/src/congestion_control.rs | 6 +++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/chain/chain/src/runtime/mod.rs b/chain/chain/src/runtime/mod.rs index 9fdf5028a72..2bba53c5ac1 100644 --- a/chain/chain/src/runtime/mod.rs +++ b/chain/chain/src/runtime/mod.rs @@ -825,7 +825,7 @@ impl RuntimeAdapter for NightshadeRuntime { if ProtocolFeature::CongestionControl.enabled(protocol_version) { let receiving_shard = EpochManagerAdapter::account_id_to_shard_id( self.epoch_manager.as_ref(), - &tx.transaction.receiver_id, + tx.transaction.receiver_id(), &epoch_id, )?; if let Some(shard_congestion) = diff --git a/integration-tests/src/tests/client/features/yield_timeouts.rs b/integration-tests/src/tests/client/features/yield_timeouts.rs index c3b383ac702..476edb51c36 100644 --- a/integration-tests/src/tests/client/features/yield_timeouts.rs +++ b/integration-tests/src/tests/client/features/yield_timeouts.rs @@ -41,10 +41,10 @@ fn find_yield_data_ids_from_latest_block(env: &TestEnv) -> Vec { .get_outgoing_receipts_for_shard(last_block_hash, shard_id, last_block_height) .unwrap() { - if let PromiseYield(ref action_receipt) = receipt.receipt { + if let PromiseYield(ref action_receipt) = receipt.receipt() { result.push(action_receipt.input_data_ids[0]); } - if let PromiseResume(ref data_receipt) = receipt.receipt { + if let PromiseResume(ref data_receipt) = receipt.receipt() { result.push(data_receipt.data_id); } } @@ -77,6 +77,7 @@ fn prepare_env_with_yield( code: near_test_contracts::nightly_rs_contract().to_vec(), })], *genesis_block.hash(), + 0, ); let tx_hash = tx.get_hash(); assert_eq!(env.clients[0].process_tx(tx, false, false), ProcessTxResponse::ValidTx); @@ -103,6 +104,7 @@ fn prepare_env_with_yield( deposit: 0, }))], *genesis_block.hash(), + 0, ); let yield_tx_hash = yield_transaction.get_hash(); assert_eq!( @@ -145,6 +147,7 @@ fn invoke_yield_resume( deposit: 0, }))], *genesis_block.hash(), + 0, ); let tx_hash = resume_transaction.get_hash(); assert_eq!( @@ -177,6 +180,7 @@ fn create_congestion(env: &mut TestEnv) { deposit: 0, }))], *genesis_block.hash(), + 0, ); tx_hashes.push(signed_transaction.get_hash()); assert_eq!( diff --git a/runtime/runtime/src/congestion_control.rs b/runtime/runtime/src/congestion_control.rs index d5b73e9e981..85d233e9463 100644 --- a/runtime/runtime/src/congestion_control.rs +++ b/runtime/runtime/src/congestion_control.rs @@ -186,7 +186,7 @@ impl ReceiptSinkV2<'_> { epoch_info_provider: &dyn EpochInfoProvider, ) -> Result<(), RuntimeError> { let shard = epoch_info_provider - .account_id_to_shard_id(&receipt.receiver_id, &apply_state.epoch_id)?; + .account_id_to_shard_id(receipt.receiver_id(), &apply_state.epoch_id)?; if shard == apply_state.shard_id { // No limits on receipts that stay on the same shard. Backpressure // wouldn't help, the receipt takes the same memory if buffered or @@ -260,11 +260,11 @@ fn receipt_congestion_gas( receipt: &Receipt, config: &RuntimeConfig, ) -> Result { - match &receipt.receipt { + match receipt.receipt() { ReceiptEnum::Action(action_receipt) => { // account for gas guaranteed to be used for executing the receipts let prepaid_exec_gas = safe_add_gas( - total_prepaid_exec_fees(config, &action_receipt.actions, &receipt.receiver_id)?, + total_prepaid_exec_fees(config, &action_receipt.actions, receipt.receiver_id())?, config.fees.fee(ActionCosts::new_action_receipt).exec_fee(), )?; // account for gas guaranteed to be used for creating new receipts From 318ffdd0fe9412dd2f78a1584d2c0eed2f0db65e Mon Sep 17 00:00:00 2001 From: Bowen Wang Date: Mon, 13 May 2024 17:15:35 -0700 Subject: [PATCH 6/8] fix receipt serde serialization --- core/primitives/src/receipt.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/primitives/src/receipt.rs b/core/primitives/src/receipt.rs index 23c8a9e7c42..293e1728a2b 100644 --- a/core/primitives/src/receipt.rs +++ b/core/primitives/src/receipt.rs @@ -80,6 +80,7 @@ pub struct ReceiptV1 { } #[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] pub enum Receipt { V0(ReceiptV0), V1(ReceiptV1), From 49a2265965f62624bb9a309f55fe51f319942531 Mon Sep 17 00:00:00 2001 From: Bowen Wang Date: Mon, 13 May 2024 18:30:22 -0700 Subject: [PATCH 7/8] fix tests --- chain/jsonrpc/res/rpc_errors_schema.json | 3 ++- integration-tests/src/tests/client/epoch_sync.rs | 2 ++ .../src/tests/client/features/nonrefundable_transfer.rs | 1 + integration-tests/src/tests/client/resharding.rs | 2 ++ integration-tests/src/tests/client/sandbox.rs | 3 ++- 5 files changed, 9 insertions(+), 2 deletions(-) diff --git a/chain/jsonrpc/res/rpc_errors_schema.json b/chain/jsonrpc/res/rpc_errors_schema.json index 5725f0c95e1..c346e73a99e 100644 --- a/chain/jsonrpc/res/rpc_errors_schema.json +++ b/chain/jsonrpc/res/rpc_errors_schema.json @@ -563,7 +563,8 @@ "InvalidChain", "Expired", "ActionsValidation", - "TransactionSizeExceeded" + "TransactionSizeExceeded", + "InvalidTransactionVersion" ], "props": {} }, diff --git a/integration-tests/src/tests/client/epoch_sync.rs b/integration-tests/src/tests/client/epoch_sync.rs index 95931a702a3..1b5c1f18d2c 100644 --- a/integration-tests/src/tests/client/epoch_sync.rs +++ b/integration-tests/src/tests/client/epoch_sync.rs @@ -48,6 +48,7 @@ fn generate_transactions(last_hash: &CryptoHash, h: BlockHeight) -> Vec Vec, ) -> ProcessTxResponse { let hash = env.clients[0].chain.head().unwrap().last_block_hash; - let tx = SignedTransaction::from_actions(nonce, signer_id, receiver_id, signer, actions, hash); + let tx = + SignedTransaction::from_actions(nonce, signer_id, receiver_id, signer, actions, hash, 0); env.clients[0].process_tx(tx, false, false) } From 791f94a6370f6a6a515a1d35e06b9114a3d6df5c Mon Sep 17 00:00:00 2001 From: Bowen Wang Date: Tue, 14 May 2024 06:50:43 -0700 Subject: [PATCH 8/8] fix --- chain/jsonrpc/res/rpc_errors_schema.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/chain/jsonrpc/res/rpc_errors_schema.json b/chain/jsonrpc/res/rpc_errors_schema.json index c346e73a99e..a09dfebc2fe 100644 --- a/chain/jsonrpc/res/rpc_errors_schema.json +++ b/chain/jsonrpc/res/rpc_errors_schema.json @@ -547,6 +547,11 @@ "account_id": "" } }, + "InvalidTransactionVersion": { + "name": "InvalidTransactionVersion", + "subtypes": [], + "props": {} + }, "InvalidTxError": { "name": "InvalidTxError", "subtypes": [