diff --git a/core/application/src/state.rs b/core/application/src/state.rs index 0c7db7393..b97781bb1 100644 --- a/core/application/src/state.rs +++ b/core/application/src/state.rs @@ -265,6 +265,7 @@ impl State { UpdateMethod::UpdateContentRegistry { updates } => { self.update_content_registry(txn.payload.sender, updates) }, + UpdateMethod::IncrementNonce {} => TransactionResponse::Success(ExecutionData::None), }; #[cfg(debug_assertions)] diff --git a/core/signer/src/lib.rs b/core/signer/src/lib.rs index 7662e90e8..a46ed2c6f 100644 --- a/core/signer/src/lib.rs +++ b/core/signer/src/lib.rs @@ -212,35 +212,50 @@ impl SignerState { self.next_nonce = self.base_nonce + 1; // Resend all transactions in the buffer. - self.pending_transactions.retain_mut(|tx| { - if let TransactionResponse::Revert(_) = - query_runner.simulate_txn(tx.update_request.clone().into()) + for tx in self.pending_transactions.iter_mut() { + if matches!( + query_runner.simulate_txn(tx.update_request.clone().into()), + TransactionResponse::Revert(_) + ) || tx.tries >= MAX_RETRIES { - // If transaction reverts, don't retry. - false - } else if tx.tries < MAX_RETRIES { - if tx.update_request.payload.nonce != self.next_nonce { - tx.update_request.payload.nonce = self.next_nonce; - tx.update_request.payload.secondary_nonce = self.next_secondary_nonce; - - let digest = tx.update_request.payload.to_digest(); - let signature = self.node_secret_key.sign(&digest); - tx.update_request.signature = signature.into(); - } - - // Update timestamp to resending time. - tx.timestamp = SystemTime::now(); - if self.base_timestamp.is_none() { - self.base_timestamp = Some(tx.timestamp); - } - - self.next_nonce += 1; - self.next_secondary_nonce += 1; - true - } else { - false + // If transaction reverts or we reached the maximum number of retries, don't + // retry again. + // To prevent invalidating the nonces of the following pending transactions, + // we have to increment the nonce on the application state. + let method = UpdateMethod::IncrementNonce {}; + let update_payload = UpdatePayload { + sender: TransactionSender::NodeMain(self.node_public_key), + method, + nonce: self.next_nonce, + secondary_nonce: self.next_secondary_nonce, + chain_id: self.chain_id.unwrap(), + }; + let digest = update_payload.to_digest(); + let signature = self.node_secret_key.sign(&digest); + let update_request = UpdateRequest { + signature: signature.into(), + payload: update_payload, + }; + tx.update_request = update_request; + } else if tx.update_request.payload.nonce != self.next_nonce { + // Note: with the change to using the increment nonce txn, this check + // should not be necessary anymore. + tx.update_request.payload.nonce = self.next_nonce; + tx.update_request.payload.secondary_nonce = self.next_secondary_nonce; + + let digest = tx.update_request.payload.to_digest(); + let signature = self.node_secret_key.sign(&digest); + tx.update_request.signature = signature.into(); + } + // Update timestamp to resending time. + tx.timestamp = SystemTime::now(); + if self.base_timestamp.is_none() { + self.base_timestamp = Some(tx.timestamp); } - }); + + self.next_nonce += 1; + self.next_secondary_nonce += 1; + } for pending_tx in self.pending_transactions.iter_mut() { if let Err(e) = self diff --git a/core/types/src/transaction.rs b/core/types/src/transaction.rs index 5ed56751a..5963b615f 100644 --- a/core/types/src/transaction.rs +++ b/core/types/src/transaction.rs @@ -424,6 +424,8 @@ pub enum UpdateMethod { /// provided by the network and the corresponding nodes that /// are providing that content. UpdateContentRegistry { updates: Vec }, + /// Increment the node nonce. + IncrementNonce {}, } impl ToDigest for UpdatePayload { @@ -642,6 +644,9 @@ impl ToDigest for UpdatePayload { .with("remove", &(update.remove as u8)); } }, + UpdateMethod::IncrementNonce {} => { + transcript_builder = transcript_builder.with("transaction_name", &"inc_nonce"); + }, } transcript_builder