Skip to content

Commit

Permalink
Merge pull request #126 from chainbound/fix/validate-chain-id
Browse files Browse the repository at this point in the history
fix: validate tx chain id
  • Loading branch information
merklefruit authored Jul 11, 2024
2 parents 6091199 + 3646323 commit f752b98
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 0 deletions.
5 changes: 5 additions & 0 deletions bolt-sidecar/src/client/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ impl RpcClient {
Self(client)
}

/// Get the chain ID.
pub async fn get_chain_id(&self) -> TransportResult<u64> {
self.0.request("eth_chainId", ()).await
}

/// Get the basefee of the latest block.
pub async fn get_basefee(&self, block_number: Option<u64>) -> TransportResult<u128> {
let tag = block_number.map_or(BlockNumberOrTag::Latest, BlockNumberOrTag::Number);
Expand Down
9 changes: 9 additions & 0 deletions bolt-sidecar/src/primitives/commitment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ impl InclusionRequest {
}
true
}

/// Validates the transaction chain id against the provided chain id.
/// Returns true if the chain id matches, false otherwise.
pub fn validate_chain_id(&self, chain_id: u64) -> bool {
match self.tx.chain_id() {
Some(tx_chain_id) if tx_chain_id == chain_id => true,
_ => false,
}
}
}

fn deserialize_tx_signed<'de, D>(deserializer: D) -> Result<TransactionSigned, D::Error>
Expand Down
12 changes: 12 additions & 0 deletions bolt-sidecar/src/state/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ pub enum ValidationError {
/// Could not recover signature,
#[error("Could not recover signer")]
RecoverSigner,
/// The transaction chain ID does not match the expected chain ID.
#[error("Chain ID mismatch")]
ChainIdMismatch,
/// NOTE: this should not be exposed to the user.
#[error("Internal error: {0}")]
Internal(String),
Expand Down Expand Up @@ -79,6 +82,9 @@ pub struct ExecutionState<C> {
/// proposal duties for a single lookahead.
block_templates: HashMap<Slot, BlockTemplate>,

/// The chain ID of the chain (constant).
chain_id: u64,

/// The state fetcher client.
client: C,
}
Expand All @@ -93,6 +99,7 @@ impl<C: StateFetcher> ExecutionState<C> {
slot: 0,
account_states: HashMap::new(),
block_templates: HashMap::new(),
chain_id: client.get_chain_id().await?,
client,
})
}
Expand All @@ -118,6 +125,11 @@ impl<C: StateFetcher> ExecutionState<C> {
pub async fn try_commit(&mut self, request: &CommitmentRequest) -> Result<(), ValidationError> {
let CommitmentRequest::Inclusion(req) = request;

// Validate the chain ID
if !req.validate_chain_id(self.chain_id) {
return Err(ValidationError::ChainIdMismatch);
}

let sender = req.tx.recover_signer().ok_or(ValidationError::Internal(
"Failed to recover signer from transaction".to_string(),
))?;
Expand Down
6 changes: 6 additions & 0 deletions bolt-sidecar/src/state/fetcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ pub trait StateFetcher {
address: &Address,
block_number: Option<u64>,
) -> Result<AccountState, TransportError>;

async fn get_chain_id(&self) -> Result<u64, TransportError>;
}

/// A basic state fetcher that uses an RPC client to fetch state updates.
Expand Down Expand Up @@ -177,6 +179,10 @@ impl StateFetcher for StateClient {
}
}
}

async fn get_chain_id(&self) -> Result<u64, TransportError> {
self.client.get_chain_id().await
}
}

#[cfg(test)]
Expand Down

0 comments on commit f752b98

Please sign in to comment.