Improve provided handling (#381)

* fix typos

* remove tributary sleeping

* handle not locally provided txs

* use topic number instead of waiting list

* Clean-up, fixes

1) Uses a single TXN in provided
2) Doesn't continue on non-local provided inside verify_block, skipping further
   execution of checks
3) Upon local provision of already on-chain TX, compares

---------

Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
This commit is contained in:
akildemir
2023-10-14 02:45:47 +03:00
committed by GitHub
parent f6e8bc3352
commit d5c6ed1a03
12 changed files with 363 additions and 102 deletions

View File

@@ -33,7 +33,10 @@ pub enum BlockError {
/// An unsigned transaction which was already added to the chain was present again.
#[error("an unsigned transaction which was already added to the chain was present again")]
UnsignedAlreadyIncluded,
/// Transactions weren't ordered as expected (Provided, followed by Unsigned, folowed by Signed).
/// A provided transaction which was already added to the chain was present again.
#[error("an provided transaction which was already added to the chain was present again")]
ProvidedAlreadyIncluded,
/// Transactions weren't ordered as expected (Provided, followed by Unsigned, followed by Signed).
#[error("transactions weren't ordered as expected (Provided, Unsigned, Signed)")]
WrongTransactionOrder,
/// The block had a provided transaction this validator has yet to be provided.
@@ -175,6 +178,8 @@ impl<T: TransactionTrait> Block<T> {
schema: N::SignatureScheme,
commit: impl Fn(u32) -> Option<Commit<N::SignatureScheme>>,
unsigned_in_chain: impl Fn([u8; 32]) -> bool,
provided_in_chain: impl Fn([u8; 32]) -> bool, // TODO: merge this with unsigned_on_chain?
allow_non_local_provided: bool,
) -> Result<(), BlockError> {
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum Order {
@@ -209,18 +214,22 @@ impl<T: TransactionTrait> Block<T> {
let current_tx_order = match tx.kind() {
TransactionKind::Provided(order) => {
let Some(local) = locally_provided.get_mut(order).and_then(|deque| deque.pop_front())
else {
Err(BlockError::NonLocalProvided(txs.pop().unwrap()))?
};
// Since this was a provided TX, it must be an application TX
let Transaction::Application(tx) = tx else {
Err(BlockError::NonLocalProvided(txs.pop().unwrap()))?
};
if tx != &local {
Err(BlockError::DistinctProvided)?;
if provided_in_chain(tx_hash) {
Err(BlockError::ProvidedAlreadyIncluded)?;
}
if let Some(local) = locally_provided.get_mut(order).and_then(|deque| deque.pop_front()) {
// Since this was a provided TX, it must be an application TX
let Transaction::Application(tx) = tx else {
Err(BlockError::NonLocalProvided(txs.pop().unwrap()))?
};
if tx != &local {
Err(BlockError::DistinctProvided)?;
}
} else if !allow_non_local_provided {
Err(BlockError::NonLocalProvided(txs.pop().unwrap()))?
};
Order::Provided
}
TransactionKind::Unsigned => {
@@ -241,12 +250,6 @@ impl<T: TransactionTrait> Block<T> {
}
last_tx_order = current_tx_order;
if current_tx_order == Order::Provided {
// We don't need to call verify_transaction since we did when we locally provided this
// transaction. Since it's identical, it must be valid
continue;
}
// TODO: should we modify the verify_transaction to take `Transaction<T>` or
// use this pattern of verifying tendermint Txs and app txs differently?
match tx {