diff --git a/.changelog/unreleased/improvements/3241-ferveo-cleanup.md b/.changelog/unreleased/improvements/3241-ferveo-cleanup.md new file mode 100644 index 0000000000..fc830800b7 --- /dev/null +++ b/.changelog/unreleased/improvements/3241-ferveo-cleanup.md @@ -0,0 +1,2 @@ +- Removed the remaining references to ferveo. + ([\#3241](https://github.com/anoma/namada/pull/3241)) \ No newline at end of file diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs index 3350391cdc..239e074fbf 100644 --- a/crates/sdk/src/lib.rs +++ b/crates/sdk/src/lib.rs @@ -803,7 +803,7 @@ pub mod testing { BecomeValidator, Bond, CommissionChange, ConsensusKeyChange, MetaDataChange, Redelegation, Unbond, Withdraw, }; - use namada_tx::data::{DecryptedTx, Fee, TxType, WrapperTx}; + use namada_tx::data::{Fee, TxType, WrapperTx}; use proptest::prelude::{Just, Strategy}; use proptest::{arbitrary, collection, option, prop_compose, prop_oneof}; use prost::Message; @@ -966,16 +966,6 @@ pub mod testing { } } - prop_compose! { - // Generate an arbitrary decrypted transaction - pub fn arb_decrypted_tx()(decrypted_tx in prop_oneof![ - Just(DecryptedTx::Decrypted), - Just(DecryptedTx::Undecryptable), - ]) -> DecryptedTx { - decrypted_tx - } - } - prop_compose! { // Generate an arbitrary transaction type pub fn arb_tx_type()(tx_type in prop_oneof![ diff --git a/crates/tests/src/integration/masp.rs b/crates/tests/src/integration/masp.rs index 92b9106ad9..5dc8e8ffb1 100644 --- a/crates/tests/src/integration/masp.rs +++ b/crates/tests/src/integration/masp.rs @@ -1794,7 +1794,7 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { for bytes in txs_bytes { let mut tx = namada::tx::Tx::deserialize(&bytes).unwrap(); tx.add_wrapper( - namada::tx::data::wrapper_tx::Fee { + namada::tx::data::wrapper::Fee { amount_per_gas_unit: DenominatedAmount::native(1.into()), token: native_token.clone(), }, diff --git a/crates/tx/src/data/decrypted.rs b/crates/tx/src/data/decrypted.rs deleted file mode 100644 index 6d2d8fc9ac..0000000000 --- a/crates/tx/src/data/decrypted.rs +++ /dev/null @@ -1,43 +0,0 @@ -pub use ark_bls12_381::Bls12_381 as EllipticCurve; - -/// Integration of Ferveo cryptographic primitives to enable decrypting txs. -/// *Not wasm compatible* -pub mod decrypted_tx { - use namada_core::borsh::{ - BorshDeserialize, BorshSchema, BorshSerialize, BorshSerializeExt, - }; - use namada_macros::BorshDeserializer; - #[cfg(feature = "migrations")] - use namada_migrations::*; - use sha2::{Digest, Sha256}; - - #[derive( - Clone, - Debug, - BorshSerialize, - BorshDeserialize, - BorshDeserializer, - BorshSchema, - serde::Serialize, - serde::Deserialize, - )] - /// Holds the result of attempting to decrypt - /// a transaction and the data necessary for - /// other validators to verify - pub enum DecryptedTx { - /// The decrypted payload - Decrypted, - /// The wrapper whose payload could not be decrypted - Undecryptable, - } - - impl DecryptedTx { - /// Produce a SHA-256 hash of this header - pub fn hash<'a>(&self, hasher: &'a mut Sha256) -> &'a mut Sha256 { - hasher.update(self.serialize_to_vec()); - hasher - } - } -} - -pub use decrypted_tx::*; diff --git a/crates/tx/src/data/mod.rs b/crates/tx/src/data/mod.rs index de7c6c75bd..692d498e0c 100644 --- a/crates/tx/src/data/mod.rs +++ b/crates/tx/src/data/mod.rs @@ -1,8 +1,5 @@ //! Data-Types that are used in transactions. -/// txs that contain decrypted payloads or assertions of -/// non-decryptability -pub mod decrypted; pub mod eval_vp; /// txs to manage pgf pub mod pgf; @@ -18,7 +15,6 @@ use std::fmt::{self, Display}; use std::str::FromStr; use bitflags::bitflags; -pub use decrypted::*; use namada_core::address::Address; use namada_core::borsh::{ BorshDeserialize, BorshSchema, BorshSerialize, BorshSerializeExt, diff --git a/crates/tx/src/data/wrapper.rs b/crates/tx/src/data/wrapper.rs index eb36b0a325..ba320f2cbf 100644 --- a/crates/tx/src/data/wrapper.rs +++ b/crates/tx/src/data/wrapper.rs @@ -1,264 +1,252 @@ -/// Integration of Ferveo cryptographic primitives -/// to enable encrypted txs inside of normal txs. -/// *Not wasm compatible* -pub mod wrapper_tx { - - use std::num::ParseIntError; - use std::str::FromStr; +use std::num::ParseIntError; +use std::str::FromStr; + +pub use ark_bls12_381::Bls12_381 as EllipticCurve; +use masp_primitives::transaction::Transaction; +use namada_core::address::{Address, MASP}; +use namada_core::borsh::{ + BorshDeserialize, BorshSchema, BorshSerialize, BorshSerializeExt, +}; +use namada_core::hash::Hash; +use namada_core::key::*; +use namada_core::token::{Amount, DenominatedAmount, Transfer}; +use namada_core::uint::Uint; +use namada_gas::Gas; +use namada_macros::BorshDeserializer; +#[cfg(feature = "migrations")] +use namada_migrations::*; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use thiserror::Error; + +use crate::data::TxType; +use crate::{Code, Data, Section, Tx}; + +/// Errors relating to decrypting a wrapper tx and its +/// encrypted payload from a Tx type +#[allow(missing_docs)] +#[derive(Error, Debug)] +pub enum WrapperTxErr { + #[error("The hash of the decrypted tx does not match the hash commitment")] + DecryptedHash, + #[error("The decryption did not produce a valid Tx")] + InvalidTx, + #[error("The given Tx data did not contain a valid WrapperTx")] + InvalidWrapperTx, + #[error( + "Attempted to sign WrapperTx with keypair whose public key differs \ + from that in the WrapperTx" + )] + InvalidKeyPair, + #[error("The provided unshielding tx is invalid: {0}")] + InvalidUnshield(String), + #[error("The given Tx fee amount overflowed")] + OverflowingFee, + #[error("Error while converting the denominated fee amount")] + DenominatedFeeConversion, +} - pub use ark_bls12_381::Bls12_381 as EllipticCurve; - use masp_primitives::transaction::Transaction; - use namada_core::address::{Address, MASP}; - use namada_core::borsh::{ - BorshDeserialize, BorshSchema, BorshSerialize, BorshSerializeExt, - }; - use namada_core::hash::Hash; - use namada_core::key::*; - use namada_core::token::{Amount, DenominatedAmount, Transfer}; - use namada_core::uint::Uint; - use namada_gas::Gas; - use namada_macros::BorshDeserializer; - #[cfg(feature = "migrations")] - use namada_migrations::*; - use serde::{Deserialize, Serialize}; - use sha2::{Digest, Sha256}; - use thiserror::Error; +/// A fee is an amount of a specified token +#[derive( + Debug, + Clone, + PartialEq, + BorshSerialize, + BorshDeserialize, + BorshDeserializer, + BorshSchema, + Serialize, + Deserialize, + Eq, +)] +pub struct Fee { + /// amount of fee per gas unit + pub amount_per_gas_unit: DenominatedAmount, + /// address of the token + /// TODO: This should support multi-tokens + pub token: Address, +} - use crate::data::TxType; - use crate::{Code, Data, Section, Tx}; +/// Gas limit of a transaction +#[derive( + Debug, + Clone, + Copy, + PartialEq, + BorshSerialize, + BorshDeserialize, + BorshDeserializer, + BorshSchema, + Serialize, + Deserialize, + Eq, +)] +pub struct GasLimit(u64); + +/// Round the input number up to the next highest multiple +/// of GAS_LIMIT_RESOLUTION +impl From for GasLimit { + fn from(amount: u64) -> GasLimit { + Self(amount) + } +} - /// Errors relating to decrypting a wrapper tx and its - /// encrypted payload from a Tx type - #[allow(missing_docs)] - #[derive(Error, Debug)] - pub enum WrapperTxErr { - #[error( - "The hash of the decrypted tx does not match the hash commitment" - )] - DecryptedHash, - #[error("The decryption did not produce a valid Tx")] - InvalidTx, - #[error("The given Tx data did not contain a valid WrapperTx")] - InvalidWrapperTx, - #[error( - "Attempted to sign WrapperTx with keypair whose public key \ - differs from that in the WrapperTx" - )] - InvalidKeyPair, - #[error("The provided unshielding tx is invalid: {0}")] - InvalidUnshield(String), - #[error("The given Tx fee amount overflowed")] - OverflowingFee, - #[error("Error while converting the denominated fee amount")] - DenominatedFeeConversion, +/// Get back the gas limit as a raw number +impl From for u64 { + fn from(limit: GasLimit) -> u64 { + limit.0 } +} - /// A fee is an amount of a specified token - #[derive( - Debug, - Clone, - PartialEq, - BorshSerialize, - BorshDeserialize, - BorshDeserializer, - BorshSchema, - Serialize, - Deserialize, - Eq, - )] - pub struct Fee { - /// amount of fee per gas unit - pub amount_per_gas_unit: DenominatedAmount, - /// address of the token - /// TODO: This should support multi-tokens - pub token: Address, +impl From for Uint { + fn from(limit: GasLimit) -> Self { + Uint::from_u64(limit.into()) } +} - /// Gas limit of a transaction - #[derive( - Debug, - Clone, - Copy, - PartialEq, - BorshSerialize, - BorshDeserialize, - BorshDeserializer, - BorshSchema, - Serialize, - Deserialize, - Eq, - )] - pub struct GasLimit(u64); +impl FromStr for GasLimit { + type Err = ParseIntError; - /// Round the input number up to the next highest multiple - /// of GAS_LIMIT_RESOLUTION - impl From for GasLimit { - fn from(amount: u64) -> GasLimit { - Self(amount) - } + fn from_str(s: &str) -> Result { + Ok(Self(s.parse()?)) } +} - /// Get back the gas limit as a raw number - impl From for u64 { - fn from(limit: GasLimit) -> u64 { - limit.0 - } +/// Get back the gas limit as a raw number, viewed as an Amount +impl From for Amount { + fn from(limit: GasLimit) -> Amount { + Amount::from_uint(limit.0, 0).unwrap() } +} - impl From for Uint { - fn from(limit: GasLimit) -> Self { - Uint::from_u64(limit.into()) - } +impl From for Gas { + // Derive a Gas instance with a sub amount which is exactly a whole + // amount since the limit represents gas in whole units + fn from(value: GasLimit) -> Self { + Self::from_whole_units(u64::from(value)) } +} - impl FromStr for GasLimit { - type Err = ParseIntError; +/// A transaction with an encrypted payload, an optional shielded pool +/// unshielding tx for fee payment and some non-encrypted metadata for +/// inclusion and / or verification purposes +#[derive( + Debug, + Clone, + BorshSerialize, + BorshDeserialize, + BorshDeserializer, + BorshSchema, + Serialize, + Deserialize, +)] +pub struct WrapperTx { + /// The fee to be paid for including the tx + pub fee: Fee, + /// Used for signature verification and to determine an implicit + /// account of the fee payer + pub pk: common::PublicKey, + /// Max amount of gas that can be used when executing the inner tx + pub gas_limit: GasLimit, + /// The hash of the optional, unencrypted, unshielding transaction for + /// fee payment + pub unshield_section_hash: Option, +} - fn from_str(s: &str) -> Result { - Ok(Self(s.parse()?)) +impl WrapperTx { + /// Create a new wrapper tx from the personal keypair, + /// an optional unshielding tx, and the metadata surrounding the + /// inclusion of the tx. + #[allow(clippy::too_many_arguments)] + pub fn new( + fee: Fee, + pk: common::PublicKey, + gas_limit: GasLimit, + unshield_hash: Option, + ) -> WrapperTx { + Self { + fee, + pk, + gas_limit, + unshield_section_hash: unshield_hash, } } - /// Get back the gas limit as a raw number, viewed as an Amount - impl From for Amount { - fn from(limit: GasLimit) -> Amount { - Amount::from_uint(limit.0, 0).unwrap() - } + /// Get the address of the implicit account associated + /// with the public key + /// NOTE: this is safe in case someone tried to use the masp address to + /// pay fees. All of the masp funds are kept in the established address, + /// while the implicit one has no funds leading to a tx failure + pub fn fee_payer(&self) -> Address { + Address::from(&self.pk) } - impl From for Gas { - // Derive a Gas instance with a sub amount which is exactly a whole - // amount since the limit represents gas in whole units - fn from(value: GasLimit) -> Self { - Self::from_whole_units(u64::from(value)) - } + /// Produce a SHA-256 hash of this section + pub fn hash<'a>(&self, hasher: &'a mut Sha256) -> &'a mut Sha256 { + hasher.update(self.serialize_to_vec()); + hasher } - /// A transaction with an encrypted payload, an optional shielded pool - /// unshielding tx for fee payment and some non-encrypted metadata for - /// inclusion and / or verification purposes - #[derive( - Debug, - Clone, - BorshSerialize, - BorshDeserialize, - BorshDeserializer, - BorshSchema, - Serialize, - Deserialize, - )] - pub struct WrapperTx { - /// The fee to be paid for including the tx - pub fee: Fee, - /// Used for signature verification and to determine an implicit - /// account of the fee payer - pub pk: common::PublicKey, - /// Max amount of gas that can be used when executing the inner tx - pub gas_limit: GasLimit, - /// The hash of the optional, unencrypted, unshielding transaction for - /// fee payment - pub unshield_section_hash: Option, + /// Generates the fee unshielding tx for execution. + pub fn generate_fee_unshielding( + &self, + transfer_code_hash: Hash, + transfer_code_tag: Option, + unshield: Transaction, + ) -> Result { + let mut tx = Tx::from_type(TxType::Raw); + let masp_section = tx.add_section(Section::MaspTx(unshield)); + let masp_hash = Hash( + masp_section + .hash(&mut Sha256::new()) + .finalize_reset() + .into(), + ); + + let transfer = Transfer { + source: MASP, + target: self.fee_payer(), + token: self.fee.token.clone(), + amount: self.get_tx_fee()?, + shielded: Some(masp_hash), + }; + let data = transfer.serialize_to_vec(); + tx.set_data(Data::new(data)); + tx.set_code(Code::from_hash(transfer_code_hash, transfer_code_tag)); + + Ok(tx) } - impl WrapperTx { - /// Create a new wrapper tx from unencrypted tx, the personal keypair, - /// an optional unshielding tx, and the metadata surrounding the - /// inclusion of the tx. This method constructs the signature of - /// relevant data and encrypts the transaction - #[allow(clippy::too_many_arguments)] - pub fn new( - fee: Fee, - pk: common::PublicKey, - gas_limit: GasLimit, - unshield_hash: Option, - ) -> WrapperTx { - Self { - fee, - pk, - gas_limit, - unshield_section_hash: unshield_hash, - } - } - - /// Get the address of the implicit account associated - /// with the public key - /// NOTE: this is safe in case someone tried to use the masp address to - /// pay fees. All of the masp funds are kept in the established address, - /// while the implicit one has no funds leading to a tx failure - pub fn fee_payer(&self) -> Address { - Address::from(&self.pk) - } - - /// Produce a SHA-256 hash of this section - pub fn hash<'a>(&self, hasher: &'a mut Sha256) -> &'a mut Sha256 { - hasher.update(self.serialize_to_vec()); - hasher - } - - /// Generates the fee unshielding tx for execution. - pub fn generate_fee_unshielding( - &self, - transfer_code_hash: Hash, - transfer_code_tag: Option, - unshield: Transaction, - ) -> Result { - let mut tx = Tx::from_type(TxType::Raw); - let masp_section = tx.add_section(Section::MaspTx(unshield)); - let masp_hash = Hash( - masp_section - .hash(&mut Sha256::new()) - .finalize_reset() - .into(), - ); - - let transfer = Transfer { - source: MASP, - target: self.fee_payer(), - token: self.fee.token.clone(), - amount: self.get_tx_fee()?, - shielded: Some(masp_hash), - }; - let data = transfer.serialize_to_vec(); - tx.set_data(Data::new(data)); - tx.set_code(Code::from_hash(transfer_code_hash, transfer_code_tag)); - - Ok(tx) - } - - /// Get the [`Amount`] of fees to be paid by the given wrapper. Returns - /// an error if the amount overflows - pub fn get_tx_fee(&self) -> Result { - self.fee - .amount_per_gas_unit - .checked_mul(Amount::from(self.gas_limit).into()) - .ok_or(WrapperTxErr::OverflowingFee) - } + /// Get the [`Amount`] of fees to be paid by the given wrapper. Returns + /// an error if the amount overflows + pub fn get_tx_fee(&self) -> Result { + self.fee + .amount_per_gas_unit + .checked_mul(Amount::from(self.gas_limit).into()) + .ok_or(WrapperTxErr::OverflowingFee) } +} - #[cfg(test)] - mod test_gas_limits { - use super::*; - - /// Test serializing and deserializing again gives back original object - /// Test that serializing converts GasLimit to u64 correctly - #[test] - fn test_gas_limit_roundtrip() { - let limit = GasLimit(1); - // Test serde roundtrip - let js = serde_json::to_string(&1).expect("Test failed"); - let new_limit: u64 = - serde_json::from_str(&js).expect("Test failed"); - assert_eq!(GasLimit(new_limit), limit); - - // Test borsh roundtrip - let borsh = limit.serialize_to_vec(); - assert_eq!( - limit, - BorshDeserialize::deserialize(&mut borsh.as_ref()) - .expect("Test failed") - ); - } +#[cfg(test)] +mod test_gas_limits { + use super::*; + + /// Test serializing and deserializing again gives back original object + /// Test that serializing converts GasLimit to u64 correctly + #[test] + fn test_gas_limit_roundtrip() { + let limit = GasLimit(1); + // Test serde roundtrip + let js = serde_json::to_string(&1).expect("Test failed"); + let new_limit: u64 = serde_json::from_str(&js).expect("Test failed"); + assert_eq!(GasLimit(new_limit), limit); + + // Test borsh roundtrip + let borsh = limit.serialize_to_vec(); + assert_eq!( + limit, + BorshDeserialize::deserialize(&mut borsh.as_ref()) + .expect("Test failed") + ); } } - -pub use wrapper_tx::*;