Clean the transaction definitions in the coordinator

Moves to borsh for serialization. No longer includes nonces anywhere in the TX.
This commit is contained in:
Luke Parker
2024-12-31 12:14:32 -05:00
parent 8c9441a1a5
commit 7e2b31e5da
16 changed files with 220 additions and 510 deletions

View File

@@ -135,7 +135,7 @@ impl<T: TransactionTrait> Block<T> {
// Check TXs are sorted by nonce.
let nonce = |tx: &Transaction<T>| {
if let TransactionKind::Signed(_, Signed { nonce, .. }) = tx.kind() {
*nonce
nonce
} else {
0
}

View File

@@ -323,7 +323,7 @@ impl<D: Db, T: TransactionTrait> Blockchain<D, T> {
}
TransactionKind::Signed(order, Signed { signer, nonce, .. }) => {
let next_nonce = nonce + 1;
txn.put(Self::next_nonce_key(&self.genesis, signer, &order), next_nonce.to_le_bytes());
txn.put(Self::next_nonce_key(&self.genesis, &signer, &order), next_nonce.to_le_bytes());
self.mempool.remove(&tx.hash());
}
}

View File

@@ -110,7 +110,7 @@ impl<T: TransactionTrait> Transaction<T> {
}
}
pub fn kind(&self) -> TransactionKind<'_> {
pub fn kind(&self) -> TransactionKind {
match self {
Transaction::Tendermint(tx) => tx.kind(),
Transaction::Application(tx) => tx.kind(),

View File

@@ -81,11 +81,11 @@ impl<D: Db, T: TransactionTrait> Mempool<D, T> {
}
Transaction::Application(tx) => match tx.kind() {
TransactionKind::Signed(order, Signed { signer, nonce, .. }) => {
let amount = *res.txs_per_signer.get(signer).unwrap_or(&0) + 1;
res.txs_per_signer.insert(*signer, amount);
let amount = *res.txs_per_signer.get(&signer).unwrap_or(&0) + 1;
res.txs_per_signer.insert(signer, amount);
if let Some(prior_nonce) =
res.last_nonce_in_mempool.insert((*signer, order.clone()), *nonce)
res.last_nonce_in_mempool.insert((signer, order.clone()), nonce)
{
assert_eq!(prior_nonce, nonce - 1);
}
@@ -133,14 +133,14 @@ impl<D: Db, T: TransactionTrait> Mempool<D, T> {
match app_tx.kind() {
TransactionKind::Signed(order, Signed { signer, .. }) => {
// Get the nonce from the blockchain
let Some(blockchain_next_nonce) = blockchain_next_nonce(*signer, order.clone()) else {
let Some(blockchain_next_nonce) = blockchain_next_nonce(signer, order.clone()) else {
// Not a participant
Err(TransactionError::InvalidSigner)?
};
let mut next_nonce = blockchain_next_nonce;
if let Some(mempool_last_nonce) =
self.last_nonce_in_mempool.get(&(*signer, order.clone()))
self.last_nonce_in_mempool.get(&(signer, order.clone()))
{
assert!(*mempool_last_nonce >= blockchain_next_nonce);
next_nonce = *mempool_last_nonce + 1;
@@ -148,14 +148,14 @@ impl<D: Db, T: TransactionTrait> Mempool<D, T> {
// If we have too many transactions from this sender, don't add this yet UNLESS we are
// this sender
let amount_in_pool = *self.txs_per_signer.get(signer).unwrap_or(&0) + 1;
let amount_in_pool = *self.txs_per_signer.get(&signer).unwrap_or(&0) + 1;
if !internal && (amount_in_pool > ACCOUNT_MEMPOOL_LIMIT) {
Err(TransactionError::TooManyInMempool)?;
}
verify_transaction(app_tx, self.genesis, &mut |_, _| Some(next_nonce))?;
self.last_nonce_in_mempool.insert((*signer, order.clone()), next_nonce);
self.txs_per_signer.insert(*signer, amount_in_pool);
self.last_nonce_in_mempool.insert((signer, order.clone()), next_nonce);
self.txs_per_signer.insert(signer, amount_in_pool);
}
TransactionKind::Unsigned => {
// check we have the tx in the pool/chain
@@ -205,7 +205,7 @@ impl<D: Db, T: TransactionTrait> Mempool<D, T> {
// Sort signed by nonce
let nonce = |tx: &Transaction<T>| {
if let TransactionKind::Signed(_, Signed { nonce, .. }) = tx.kind() {
*nonce
nonce
} else {
unreachable!()
}
@@ -242,11 +242,11 @@ impl<D: Db, T: TransactionTrait> Mempool<D, T> {
if let Some(tx) = self.txs.remove(tx) {
if let TransactionKind::Signed(order, Signed { signer, nonce, .. }) = tx.kind() {
let amount = *self.txs_per_signer.get(signer).unwrap() - 1;
self.txs_per_signer.insert(*signer, amount);
let amount = *self.txs_per_signer.get(&signer).unwrap() - 1;
self.txs_per_signer.insert(signer, amount);
if self.last_nonce_in_mempool.get(&(*signer, order.clone())) == Some(nonce) {
self.last_nonce_in_mempool.remove(&(*signer, order));
if self.last_nonce_in_mempool.get(&(signer, order.clone())) == Some(&nonce) {
self.last_nonce_in_mempool.remove(&(signer, order));
}
}
}

View File

@@ -39,7 +39,7 @@ impl ReadWrite for TendermintTx {
}
impl Transaction for TendermintTx {
fn kind(&self) -> TransactionKind<'_> {
fn kind(&self) -> TransactionKind {
// There's an assert elsewhere in the codebase expecting this behavior
// If we do want to add Provided/Signed TendermintTxs, review the implications carefully
TransactionKind::Unsigned

View File

@@ -60,8 +60,8 @@ impl ReadWrite for NonceTransaction {
}
impl TransactionTrait for NonceTransaction {
fn kind(&self) -> TransactionKind<'_> {
TransactionKind::Signed(vec![], &self.2)
fn kind(&self) -> TransactionKind {
TransactionKind::Signed(vec![], self.2.clone())
}
fn hash(&self) -> [u8; 32] {

View File

@@ -425,7 +425,7 @@ async fn block_tx_ordering() {
}
impl TransactionTrait for SignedTx {
fn kind(&self) -> TransactionKind<'_> {
fn kind(&self) -> TransactionKind {
match self {
SignedTx::Signed(signed) => signed.kind(),
SignedTx::Provided(pro) => pro.kind(),

View File

@@ -67,7 +67,7 @@ impl ReadWrite for ProvidedTransaction {
}
impl Transaction for ProvidedTransaction {
fn kind(&self) -> TransactionKind<'_> {
fn kind(&self) -> TransactionKind {
match self.0[0] {
1 => TransactionKind::Provided("order1"),
2 => TransactionKind::Provided("order2"),
@@ -119,8 +119,8 @@ impl ReadWrite for SignedTransaction {
}
impl Transaction for SignedTransaction {
fn kind(&self) -> TransactionKind<'_> {
TransactionKind::Signed(vec![], &self.1)
fn kind(&self) -> TransactionKind {
TransactionKind::Signed(vec![], self.1.clone())
}
fn hash(&self) -> [u8; 32] {

View File

@@ -109,7 +109,7 @@ impl Signed {
#[allow(clippy::large_enum_variant)]
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum TransactionKind<'a> {
pub enum TransactionKind {
/// This transaction should be provided by every validator, in an exact order.
///
/// The contained static string names the orderer to use. This allows two distinct provided
@@ -137,14 +137,14 @@ pub enum TransactionKind<'a> {
Unsigned,
/// A signed transaction.
Signed(Vec<u8>, &'a Signed),
Signed(Vec<u8>, Signed),
}
// TODO: Should this be renamed TransactionTrait now that a literal Transaction exists?
// Or should the literal Transaction be renamed to Event?
pub trait Transaction: 'static + Send + Sync + Clone + Eq + Debug + ReadWrite {
/// Return what type of transaction this is.
fn kind(&self) -> TransactionKind<'_>;
fn kind(&self) -> TransactionKind;
/// Return the hash of this transaction.
///
@@ -198,8 +198,8 @@ pub(crate) fn verify_transaction<F: GAIN, T: Transaction>(
match tx.kind() {
TransactionKind::Provided(_) | TransactionKind::Unsigned => {}
TransactionKind::Signed(order, Signed { signer, nonce, signature }) => {
if let Some(next_nonce) = get_and_increment_nonce(signer, &order) {
if *nonce != next_nonce {
if let Some(next_nonce) = get_and_increment_nonce(&signer, &order) {
if nonce != next_nonce {
Err(TransactionError::InvalidNonce)?;
}
} else {
@@ -208,7 +208,7 @@ pub(crate) fn verify_transaction<F: GAIN, T: Transaction>(
}
// TODO: Use a batch verification here
if !signature.verify(*signer, tx.sig_hash(genesis)) {
if !signature.verify(signer, tx.sig_hash(genesis)) {
Err(TransactionError::InvalidSignature)?;
}
}