Skip to content

Commit

Permalink
Merge branch 'grarco/replay-protection-improvements' (#1905)
Browse files Browse the repository at this point in the history
  • Loading branch information
grarco committed Nov 7, 2023
2 parents cf3c789 + 12aeb34 commit 73e8137
Show file tree
Hide file tree
Showing 40 changed files with 1,079 additions and 430 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Improved replay protection for invalid transactions.
([\#1905](https://github.com/anoma/namada/pull/1905))
353 changes: 236 additions & 117 deletions apps/src/lib/node/ledger/shell/finalize_block.rs

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions core/src/ledger/tx_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,7 @@ pub trait TxEnv: StorageRead + StorageWrite {
&self,
event_type: impl AsRef<str>,
) -> Result<Vec<IbcEvent>, storage_api::Error>;

/// Set the sentinel for an invalid section commitment
fn set_commitment_sentinel(&mut self);
}
16 changes: 9 additions & 7 deletions core/src/proto/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ use sha2::{Digest, Sha256};
use thiserror::Error;

use super::generated::types;
use crate::ledger::gas::{GasMetering, VpGasMeter, VERIFY_TX_SIG_GAS_COST};
use crate::ledger::gas::{
self, GasMetering, VpGasMeter, VERIFY_TX_SIG_GAS_COST,
};
use crate::ledger::storage::{KeccakHasher, Sha256Hasher, StorageHasher};
#[cfg(any(feature = "tendermint", feature = "tendermint-abcipp"))]
use crate::tendermint_proto::abci::ResponseDeliverTx;
Expand Down Expand Up @@ -74,8 +76,8 @@ pub enum Error {
InvalidJSONDeserialization(String),
#[error("The wrapper signature is invalid.")]
InvalidWrapperSignature,
#[error("Signature verification went out of gas")]
OutOfGas,
#[error("Signature verification went out of gas: {0}")]
OutOfGas(gas::Error),
}

pub type Result<T> = std::result::Result<T, Error>;
Expand Down Expand Up @@ -593,7 +595,7 @@ impl Signature {
if let Some(meter) = gas_meter {
meter
.consume(VERIFY_TX_SIG_GAS_COST)
.map_err(|_| VerifySigError::OutOfGas)?;
.map_err(VerifySigError::OutOfGas)?;
}
common::SigScheme::verify_signature(
&pk,
Expand All @@ -618,7 +620,7 @@ impl Signature {
if let Some(meter) = gas_meter {
meter
.consume(VERIFY_TX_SIG_GAS_COST)
.map_err(|_| VerifySigError::OutOfGas)?;
.map_err(VerifySigError::OutOfGas)?;
}
common::SigScheme::verify_signature(
pk,
Expand Down Expand Up @@ -1448,8 +1450,8 @@ impl Tx {
gas_meter,
)
.map_err(|e| {
if let VerifySigError::OutOfGas = e {
Error::OutOfGas
if let VerifySigError::OutOfGas(inner) = e {
Error::OutOfGas(inner)
} else {
Error::InvalidSectionSignature(
"found invalid signature.".to_string(),
Expand Down
4 changes: 2 additions & 2 deletions core/src/types/key/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ pub enum VerifySigError {
MissingData,
#[error("Signature belongs to a different scheme from the public key.")]
MismatchedScheme,
#[error("Signature verification went out of gas")]
OutOfGas,
#[error("Signature verification went out of gas: {0}")]
OutOfGas(crate::ledger::gas::Error),
}

#[allow(missing_docs)]
Expand Down
27 changes: 27 additions & 0 deletions core/src/types/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ pub struct VpsResult {
pub gas_used: VpsGas,
/// Errors occurred in any of the VPs, if any
pub errors: Vec<(Address, String)>,
/// Sentinel to signal an invalid transaction signature
pub invalid_sig: bool,
}

impl fmt::Display for TxResult {
Expand Down Expand Up @@ -166,6 +168,31 @@ impl TxType {
}
}

/// Sentinel used in transactions to signal events that require special
/// replay protection handling back to the protocol.
#[derive(Debug, Default)]
pub enum TxSentinel {
/// No action required
#[default]
None,
/// Exceeded gas limit
OutOfGas,
/// Found invalid commtiment to one of the transaction's sections
InvalidCommitment,
}

impl TxSentinel {
/// Set the sentinel for an out of gas error
pub fn set_out_of_gas(&mut self) {
*self = Self::OutOfGas
}

/// Set the sentinel for an invalid section commitment error
pub fn set_invalid_commitment(&mut self) {
*self = Self::InvalidCommitment
}
}

#[cfg(test)]
mod test_process_tx {
use super::*;
Expand Down
35 changes: 35 additions & 0 deletions core/src/types/validity_predicate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,38 @@ pub struct EvalVp {
/// The input for the `eval`ed VP
pub input: Tx,
}

/// Sentinel used in validity predicates to signal events that require special
/// replay protection handling back to the protocol.
#[derive(Debug, Default)]
pub enum VpSentinel {
/// No action required
#[default]
None,
/// Exceeded gas limit
OutOfGas,
/// Found invalid transaction signature
InvalidSignature,
}

impl VpSentinel {
/// Check if the Vp ran out of gas
pub fn is_out_of_gas(&self) -> bool {
matches!(self, Self::OutOfGas)
}

/// Check if the Vp found an invalid signature
pub fn is_invalid_signature(&self) -> bool {
matches!(self, Self::InvalidSignature)
}

/// Set the sentinel for an out of gas error
pub fn set_out_of_gas(&mut self) {
*self = Self::OutOfGas
}

/// Set the sentinel for an invalid signature error
pub fn set_invalid_signature(&mut self) {
*self = Self::InvalidSignature
}
}
45 changes: 39 additions & 6 deletions shared/src/ledger/native_vp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use std::collections::BTreeSet;
use borsh::BorshDeserialize;
use eyre::WrapErr;
pub use namada_core::ledger::vp_env::VpEnv;
use namada_core::types::validity_predicate::VpSentinel;

use super::storage_api::{self, ResultExt, StorageRead};
use super::vp_host_fns;
Expand Down Expand Up @@ -66,6 +67,8 @@ where
pub iterators: RefCell<PrefixIterators<'a, DB>>,
/// VP gas meter.
pub gas_meter: RefCell<VpGasMeter>,
/// Errors sentinel
pub sentinel: RefCell<VpSentinel>,
/// Read-only access to the storage.
pub storage: &'a Storage<DB, H>,
/// Read-only access to the write log.
Expand Down Expand Up @@ -136,6 +139,7 @@ where
address,
iterators: RefCell::new(PrefixIterators::default()),
gas_meter: RefCell::new(gas_meter),
sentinel: RefCell::new(VpSentinel::default()),
storage,
write_log,
tx,
Expand Down Expand Up @@ -182,6 +186,7 @@ where
self.ctx.storage,
self.ctx.write_log,
key,
&mut self.ctx.sentinel.borrow_mut(),
)
.into_storage_result()
}
Expand All @@ -195,6 +200,7 @@ where
self.ctx.storage,
self.ctx.write_log,
key,
&mut self.ctx.sentinel.borrow_mut(),
)
.into_storage_result()
}
Expand All @@ -208,6 +214,7 @@ where
self.ctx.write_log,
self.ctx.storage,
prefix,
&mut self.ctx.sentinel.borrow_mut(),
)
.into_storage_result()
}
Expand All @@ -219,8 +226,12 @@ where
&'iter self,
iter: &mut Self::PrefixIter<'iter>,
) -> Result<Option<(String, Vec<u8>)>, storage_api::Error> {
vp_host_fns::iter_next::<DB>(&mut self.ctx.gas_meter.borrow_mut(), iter)
.into_storage_result()
vp_host_fns::iter_next::<DB>(
&mut self.ctx.gas_meter.borrow_mut(),
iter,
&mut self.ctx.sentinel.borrow_mut(),
)
.into_storage_result()
}

fn get_chain_id(&self) -> Result<String, storage_api::Error> {
Expand Down Expand Up @@ -273,6 +284,7 @@ where
self.ctx.storage,
self.ctx.write_log,
key,
&mut self.ctx.sentinel.borrow_mut(),
)
.into_storage_result()
}
Expand All @@ -286,6 +298,7 @@ where
self.ctx.storage,
self.ctx.write_log,
key,
&mut self.ctx.sentinel.borrow_mut(),
)
.into_storage_result()
}
Expand All @@ -299,6 +312,7 @@ where
self.ctx.write_log,
self.ctx.storage,
prefix,
&mut self.ctx.sentinel.borrow_mut(),
)
.into_storage_result()
}
Expand All @@ -310,8 +324,12 @@ where
&'iter self,
iter: &mut Self::PrefixIter<'iter>,
) -> Result<Option<(String, Vec<u8>)>, storage_api::Error> {
vp_host_fns::iter_next::<DB>(&mut self.ctx.gas_meter.borrow_mut(), iter)
.into_storage_result()
vp_host_fns::iter_next::<DB>(
&mut self.ctx.gas_meter.borrow_mut(),
iter,
&mut self.ctx.sentinel.borrow_mut(),
)
.into_storage_result()
}

fn get_chain_id(&self) -> Result<String, storage_api::Error> {
Expand Down Expand Up @@ -372,6 +390,7 @@ where
&mut self.gas_meter.borrow_mut(),
self.write_log,
key,
&mut self.sentinel.borrow_mut(),
)
.map(|data| data.and_then(|t| T::try_from_slice(&t[..]).ok()))
.into_storage_result()
Expand All @@ -385,6 +404,7 @@ where
&mut self.gas_meter.borrow_mut(),
self.write_log,
key,
&mut self.sentinel.borrow_mut(),
)
.into_storage_result()
}
Expand All @@ -393,6 +413,7 @@ where
vp_host_fns::get_chain_id(
&mut self.gas_meter.borrow_mut(),
self.storage,
&mut self.sentinel.borrow_mut(),
)
.into_storage_result()
}
Expand All @@ -401,6 +422,7 @@ where
vp_host_fns::get_block_height(
&mut self.gas_meter.borrow_mut(),
self.storage,
&mut self.sentinel.borrow_mut(),
)
.into_storage_result()
}
Expand All @@ -413,6 +435,7 @@ where
&mut self.gas_meter.borrow_mut(),
self.storage,
height,
&mut self.sentinel.borrow_mut(),
)
.into_storage_result()
}
Expand All @@ -421,6 +444,7 @@ where
vp_host_fns::get_block_hash(
&mut self.gas_meter.borrow_mut(),
self.storage,
&mut self.sentinel.borrow_mut(),
)
.into_storage_result()
}
Expand All @@ -429,6 +453,7 @@ where
vp_host_fns::get_block_epoch(
&mut self.gas_meter.borrow_mut(),
self.storage,
&mut self.sentinel.borrow_mut(),
)
.into_storage_result()
}
Expand All @@ -437,6 +462,7 @@ where
vp_host_fns::get_tx_index(
&mut self.gas_meter.borrow_mut(),
self.tx_index,
&mut self.sentinel.borrow_mut(),
)
.into_storage_result()
}
Expand All @@ -445,6 +471,7 @@ where
vp_host_fns::get_native_token(
&mut self.gas_meter.borrow_mut(),
self.storage,
&mut self.sentinel.borrow_mut(),
)
.into_storage_result()
}
Expand All @@ -470,6 +497,7 @@ where
self.write_log,
self.storage,
prefix,
&mut self.sentinel.borrow_mut(),
)
.into_storage_result()
}
Expand Down Expand Up @@ -501,6 +529,7 @@ where
self.storage,
self.write_log,
&mut self.gas_meter.borrow_mut(),
&mut self.sentinel.borrow_mut(),
self.tx,
self.tx_index,
&mut iterators,
Expand Down Expand Up @@ -543,8 +572,12 @@ where
}

fn get_tx_code_hash(&self) -> Result<Option<Hash>, storage_api::Error> {
vp_host_fns::get_tx_code_hash(&mut self.gas_meter.borrow_mut(), self.tx)
.into_storage_result()
vp_host_fns::get_tx_code_hash(
&mut self.gas_meter.borrow_mut(),
self.tx,
&mut self.sentinel.borrow_mut(),
)
.into_storage_result()
}

fn read_pre<T: borsh::BorshDeserialize>(
Expand Down
Loading

0 comments on commit 73e8137

Please sign in to comment.