Skip to content

Commit

Permalink
feat(l1_provider): add validate action (#2211)
Browse files Browse the repository at this point in the history
Co-Authored-By: Gilad Chase <gilad@starkware.com>
  • Loading branch information
giladchase and Gilad Chase authored Nov 24, 2024
1 parent bd62ab3 commit 2450cca
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 10 deletions.
6 changes: 5 additions & 1 deletion crates/starknet_l1_provider/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ pub enum L1ProviderError {
GetTransactionConsensusBug,
#[error("Cannot transition from {from} to {to}")]
UnexpectedProviderStateTransition { from: ProviderState, to: ProviderState },
#[error("`validate_tx` called while in proposal state")]
#[error(
"`validate` called while in `Pending` state, likely due to a crash; restart block proposal"
)]
ValidateInPendingState,
#[error("`validate` called while in `Propose`")]
ValidateTransactionConsensusBug,
}
30 changes: 29 additions & 1 deletion crates/starknet_l1_provider/src/l1_provider_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use starknet_api::transaction::TransactionHash;

use crate::errors::L1ProviderError;
use crate::test_utils::L1ProviderContentBuilder;
use crate::L1Provider;
use crate::ProviderState::{Propose, Validate};
use crate::{L1Provider, ValidationStatus};

macro_rules! tx {
(tx_hash: $tx_hash:expr) => {{
Expand All @@ -20,6 +20,12 @@ macro_rules! tx {
}};
}

macro_rules! tx_hash {
($tx_hash:expr) => {
TransactionHash(StarkHash::from($tx_hash))
};
}

#[test]
fn get_txs_happy_flow() {
// Setup.
Expand All @@ -36,6 +42,23 @@ fn get_txs_happy_flow() {
assert_eq!(l1_provider.get_txs(1).unwrap(), []);
}

#[test]
fn validate_happy_flow() {
// Setup.
let l1_provider = L1ProviderContentBuilder::new()
.with_txs([tx!(tx_hash: 1)])
.with_on_l2_awaiting_l1_consumption([tx_hash!(2)])
.with_state(Validate)
.build_into_l1_provider();

// Test.
assert_eq!(l1_provider.validate(tx_hash!(1)).unwrap(), ValidationStatus::Validated);
assert_eq!(l1_provider.validate(tx_hash!(2)).unwrap(), ValidationStatus::AlreadyIncludedOnL2);
assert_eq!(l1_provider.validate(tx_hash!(3)).unwrap(), ValidationStatus::ConsumedOnL1OrUnknown);
// Transaction wasn't deleted after the validation.
assert_eq!(l1_provider.validate(tx_hash!(1)).unwrap(), ValidationStatus::Validated);
}

#[test]
fn pending_state_errors() {
// Setup.
Expand All @@ -47,6 +70,11 @@ fn pending_state_errors() {
l1_provider.get_txs(1).unwrap_err(),
L1ProviderError::GetTransactionsInPendingState
);

assert_matches!(
l1_provider.validate(tx_hash!(1)).unwrap_err(),
L1ProviderError::ValidateInPendingState
);
}

#[test]
Expand Down
33 changes: 26 additions & 7 deletions crates/starknet_l1_provider/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ impl L1Provider {
}
}

pub fn validate(&self, _tx: &L1HandlerTransaction) -> L1ProviderResult<bool> {
todo!(
"Check that tx is unconsumed and not present in L2. Error if in Propose state, NOP if \
in pending state (likely due to a crash and losing one validator for the block's \
duration node isn't serious)."
)
/// Returns true if and only if the given transaction is both not included in an L2 block, and
/// unconsumed on L1.
pub fn validate(&self, tx_hash: TransactionHash) -> L1ProviderResult<ValidationStatus> {
match self.state {
ProviderState::Validate => Ok(self.tx_manager.tx_status(tx_hash)),
ProviderState::Propose => Err(L1ProviderError::ValidateTransactionConsensusBug),
ProviderState::Pending => Err(L1ProviderError::ValidateInPendingState),
}
}

// TODO: when deciding on consensus, if possible, have commit_block also tell the node if it's
Expand Down Expand Up @@ -99,7 +101,7 @@ impl L1Provider {
struct TransactionManager {
txs: IndexMap<TransactionHash, L1HandlerTransaction>,
proposed_txs: IndexSet<TransactionHash>,
_on_l2_awaiting_l1_consumption: IndexSet<TransactionHash>,
on_l2_awaiting_l1_consumption: IndexSet<TransactionHash>,
}

impl TransactionManager {
Expand All @@ -116,6 +118,16 @@ impl TransactionManager {
txs
}

pub fn tx_status(&self, tx_hash: TransactionHash) -> ValidationStatus {
if self.txs.contains_key(&tx_hash) {
ValidationStatus::Validated
} else if self.on_l2_awaiting_l1_consumption.contains(&tx_hash) {
ValidationStatus::AlreadyIncludedOnL2
} else {
ValidationStatus::ConsumedOnL1OrUnknown
}
}

pub fn _add_unconsumed_l1_not_in_l2_block_tx(&mut self, _tx: L1HandlerTransaction) {
todo!(
"Check if tx is in L2, if it isn't on L2 add it to the txs buffer, otherwise print
Expand All @@ -128,6 +140,13 @@ impl TransactionManager {
}
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ValidationStatus {
Validated,
AlreadyIncludedOnL2,
ConsumedOnL1OrUnknown,
}

/// Current state of the provider, where pending means: idle, between proposal/validation cycles.
#[derive(Clone, Copy, Debug, Default)]
pub enum ProviderState {
Expand Down
2 changes: 1 addition & 1 deletion crates/starknet_l1_provider/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl TransactionManagerContent {
fn complete_to_tx_manager(self) -> TransactionManager {
TransactionManager {
txs: self.txs.unwrap_or_default(),
_on_l2_awaiting_l1_consumption: self.on_l2_awaiting_l1_consumption.unwrap_or_default(),
on_l2_awaiting_l1_consumption: self.on_l2_awaiting_l1_consumption.unwrap_or_default(),
..Default::default()
}
}
Expand Down

0 comments on commit 2450cca

Please sign in to comment.