Skip to content

Commit

Permalink
Introduce priority fee field for transaction and receipt (#11228)
Browse files Browse the repository at this point in the history
A first step towards near/NEPs#541 by
introducing a priority field in both transaction and receipt. This is
not entirely trivial due to the need to maintain backward compatibility.
This PR accomplishes backward compatibility by leveraging the account id
serialization and implement manual deserialization for the new
transaction and receipt structures. While this PR appears to be quite
large, most of the changes are trivial. The core of the changes are the
serialization/deserialization of transaction and receipt.

While this change introduces the new versions, they are prohibited from
being used in the current protocol until the introduction of the
protocol change that leverages priorities.
  • Loading branch information
bowenwang1996 authored May 14, 2024
1 parent 645f72e commit a9a6eff
Show file tree
Hide file tree
Showing 77 changed files with 1,279 additions and 529 deletions.
10 changes: 5 additions & 5 deletions chain/chain/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3011,7 +3011,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))?;
Expand All @@ -3029,7 +3029,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()
Expand Down Expand Up @@ -4406,7 +4406,7 @@ impl Chain {
) -> HashMap<ShardId, Vec<Receipt>> {
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)
}
Expand All @@ -4427,8 +4427,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);
Expand Down
5 changes: 4 additions & 1 deletion chain/chain/src/chain_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,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)
Expand Down
7 changes: 3 additions & 4 deletions chain/chain/src/garbage_collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -876,10 +876,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::<Vec<_>>())
{
match self.get_outgoing_receipts(block_hash, shard_id).map(|receipts| {
receipts.iter().map(|receipt| *receipt.receipt_id()).collect::<Vec<_>>()
}) {
Ok(receipt_ids) => {
for receipt_id in receipt_ids {
let key: Vec<u8> = receipt_id.into();
Expand Down
4 changes: 2 additions & 2 deletions chain/chain/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,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(
Expand Down Expand Up @@ -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(congestion_info) =
Expand Down
7 changes: 5 additions & 2 deletions chain/chain/src/runtime/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ fn stake(
vec![Action::Stake(Box::new(StakeAction { stake, public_key: sender.public_key() }))],
// runtime does not validate block history
CryptoHash::default(),
0,
)
}

Expand Down Expand Up @@ -356,7 +357,7 @@ impl TestEnv {
let shard_layout = self.epoch_manager.get_shard_layout_from_prev_block(&new_hash).unwrap();
let mut new_receipts = HashMap::<_, Vec<Receipt>>::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;
Expand Down Expand Up @@ -1390,6 +1391,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 {
Expand Down Expand Up @@ -1481,6 +1483,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 {
Expand Down Expand Up @@ -1651,7 +1654,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()
Expand Down
10 changes: 5 additions & 5 deletions chain/chain/src/store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,12 +383,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
Expand Down Expand Up @@ -689,7 +689,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(())
}
Expand Down Expand Up @@ -1977,7 +1977,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));
}
Expand Down
6 changes: 3 additions & 3 deletions chain/chain/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,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};

Expand All @@ -293,7 +293,7 @@ mod test {
let shard_receipts: Vec<Receipt> = 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();
Expand All @@ -305,7 +305,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(|_| {
Expand Down
48 changes: 26 additions & 22 deletions chain/chain/src/test_utils/kv_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,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;
Expand Down Expand Up @@ -1145,16 +1145,19 @@ 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,
));
Expand All @@ -1169,36 +1172,37 @@ 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 {
Expand Down Expand Up @@ -1229,7 +1233,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),
Expand All @@ -1241,7 +1245,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]
Expand Down
4 changes: 2 additions & 2 deletions chain/chain/src/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
6 changes: 3 additions & 3 deletions chain/chunks/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,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);
}
Expand Down Expand Up @@ -266,8 +266,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);
}
Expand Down
9 changes: 5 additions & 4 deletions chain/client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,7 @@ impl Client {
"other".parse().unwrap(),
3,
prev_block_hash,
0,
),
));
if txs.storage_proof.is_none() {
Expand Down Expand Up @@ -2118,7 +2119,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()?;
Expand All @@ -2135,7 +2136,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,
Expand Down Expand Up @@ -2226,7 +2227,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");
Expand All @@ -2247,7 +2248,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 =
Expand Down
2 changes: 2 additions & 0 deletions chain/client/src/test_utils/test_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,7 @@ impl TestEnv {
signer,
actions,
tip.last_block_hash,
0,
)
}

Expand Down Expand Up @@ -735,6 +736,7 @@ impl TestEnv {
&relayer_signer,
vec![Action::Delegate(Box::new(signed_delegate_action))],
tip.last_block_hash,
0,
)
}

Expand Down
Loading

0 comments on commit a9a6eff

Please sign in to comment.