diff --git a/applications/minotari_console_wallet/src/ui/components/transactions_tab.rs b/applications/minotari_console_wallet/src/ui/components/transactions_tab.rs index ee7e66e9f6..454b6c0d4f 100644 --- a/applications/minotari_console_wallet/src/ui/components/transactions_tab.rs +++ b/applications/minotari_console_wallet/src/ui/components/transactions_tab.rs @@ -432,7 +432,7 @@ impl TransactionsTab { }; let maturity = Span::styled(maturity, Style::default().fg(Color::White)); - let payment_id = match tx.payment_id { + let payment_id = match &tx.payment_id { Some(v) => format!("#{}", v), None => "None".to_string(), }; diff --git a/base_layer/common_types/src/tari_address/mod.rs b/base_layer/common_types/src/tari_address/mod.rs index 3e133e6603..432045b6e1 100644 --- a/base_layer/common_types/src/tari_address/mod.rs +++ b/base_layer/common_types/src/tari_address/mod.rs @@ -20,7 +20,7 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -mod dual_address; +pub mod dual_address; mod single_address; use std::{ diff --git a/base_layer/core/src/consensus/consensus_constants.rs b/base_layer/core/src/consensus/consensus_constants.rs index a75e421787..9b42506016 100644 --- a/base_layer/core/src/consensus/consensus_constants.rs +++ b/base_layer/core/src/consensus/consensus_constants.rs @@ -98,7 +98,7 @@ pub struct ConsensusConstants { /// Maximum byte size of TariScript max_script_byte_size: usize, /// Maximum byte size of encrypted data - max_encrypted_data_byte_size: usize, + max_extra_encrypted_data_byte_size: usize, /// Range of valid transaction input versions input_version_range: RangeInclusive, /// Range of valid transaction output (and features) versions @@ -277,8 +277,8 @@ impl ConsensusConstants { } /// The maximum serialized byte size of TariScript - pub fn max_encrypted_data_byte_size(&self) -> usize { - self.max_encrypted_data_byte_size + pub fn max_extra_encrypted_data_byte_size(&self) -> usize { + self.max_extra_encrypted_data_byte_size } /// This is the min initial difficulty that can be requested for the pow @@ -404,7 +404,7 @@ impl ConsensusConstants { faucet_value: 0.into(), transaction_weight: TransactionWeight::latest(), max_script_byte_size: 2048, - max_encrypted_data_byte_size: 32, // U256 size + max_extra_encrypted_data_byte_size: 256, input_version_range, output_version_range, kernel_version_range, @@ -469,7 +469,7 @@ impl ConsensusConstants { faucet_value: 0.into(), // IGOR_FAUCET_VALUE.into(), transaction_weight: TransactionWeight::v1(), max_script_byte_size: 2048, - max_encrypted_data_byte_size: 32, // U256 size + max_extra_encrypted_data_byte_size: 256, input_version_range, output_version_range, kernel_version_range, @@ -527,7 +527,7 @@ impl ConsensusConstants { faucet_value: ESMERALDA_FAUCET_VALUE.into(), transaction_weight: TransactionWeight::v1(), max_script_byte_size: 2048, - max_encrypted_data_byte_size: 32, // U256 size + max_extra_encrypted_data_byte_size: 256, input_version_range, output_version_range, kernel_version_range, @@ -584,7 +584,7 @@ impl ConsensusConstants { faucet_value: FAUCET_VALUE.into(), transaction_weight: TransactionWeight::v1(), max_script_byte_size: 2048, - max_encrypted_data_byte_size: 32, // U256 size + max_extra_encrypted_data_byte_size: 256, input_version_range, output_version_range, kernel_version_range, @@ -635,7 +635,7 @@ impl ConsensusConstants { faucet_value: FAUCET_VALUE.into(), transaction_weight: TransactionWeight::v1(), max_script_byte_size: 2048, - max_encrypted_data_byte_size: 32, // U256 size + max_extra_encrypted_data_byte_size: 256, input_version_range, output_version_range, kernel_version_range, @@ -688,7 +688,7 @@ impl ConsensusConstants { faucet_value: MicroMinotari::from(0), transaction_weight: TransactionWeight::v1(), max_script_byte_size: 2048, - max_encrypted_data_byte_size: 32, // U256 size + max_extra_encrypted_data_byte_size: 256, input_version_range, output_version_range, kernel_version_range, diff --git a/base_layer/core/src/transactions/coinbase_builder.rs b/base_layer/core/src/transactions/coinbase_builder.rs index a1d28c262b..9b9fe63012 100644 --- a/base_layer/core/src/transactions/coinbase_builder.rs +++ b/base_layer/core/src/transactions/coinbase_builder.rs @@ -317,7 +317,7 @@ where TKeyManagerInterface: TransactionKeyManagerInterface &spending_key_id, Some(&encryption_key_id), total_reward.into(), - payment_id, + payment_id.clone(), ) .await?; let minimum_value_promise = match range_proof_type { diff --git a/base_layer/core/src/transactions/transaction_components/encrypted_data.rs b/base_layer/core/src/transactions/transaction_components/encrypted_data.rs index 8bf2b10592..796c806233 100644 --- a/base_layer/core/src/transactions/transaction_components/encrypted_data.rs +++ b/base_layer/core/src/transactions/transaction_components/encrypted_data.rs @@ -44,7 +44,10 @@ use chacha20poly1305::{ use digest::{consts::U32, generic_array::GenericArray, FixedOutput}; use primitive_types::U256; use serde::{Deserialize, Serialize}; -use tari_common_types::types::{Commitment, PrivateKey}; +use tari_common_types::{ + tari_address::dual_address::DualAddress, + types::{Commitment, PrivateKey}, +}; use tari_crypto::{hashing::DomainSeparatedHasher, keys::SecretKey}; use tari_hashing::TransactionSecureNonceKdfDomain; use tari_utilities::{ @@ -75,45 +78,43 @@ pub struct EncryptedData { data: Vec, } -#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] pub enum PaymentId { Zero, - U32(u32), U64(u64), U256(U256), + Address(DualAddress), + Open(Vec), } impl PaymentId { pub fn get_size(&self) -> usize { match self { PaymentId::Zero => 0, - PaymentId::U32(_) => size_of::(), PaymentId::U64(_) => size_of::(), PaymentId::U256(_) => size_of::(), + PaymentId::Address(_) => 67, + PaymentId::Open(v) => v.len(), } } pub fn as_bytes(&self) -> Vec { match self { PaymentId::Zero => Vec::new(), - PaymentId::U32(v) => (*v).to_le_bytes().to_vec(), PaymentId::U64(v) => (*v).to_le_bytes().to_vec(), PaymentId::U256(v) => { let mut bytes = vec![0; 32]; v.to_little_endian(&mut bytes); bytes }, + PaymentId::Address(v) => v.to_bytes().to_vec(), + PaymentId::Open(v) => v.clone(), } } pub fn from_bytes(bytes: &[u8]) -> Result { match bytes.len() { 0 => Ok(PaymentId::Zero), - 4 => { - let bytes: [u8; 4] = bytes.try_into().expect("Cannot fail, as we already test the length"); - let v = u32::from_le_bytes(bytes); - Ok(PaymentId::U32(v)) - }, 8 => { let bytes: [u8; 8] = bytes.try_into().expect("Cannot fail, as we already test the length"); let v = u64::from_le_bytes(bytes); @@ -123,9 +124,12 @@ impl PaymentId { let v = U256::from_little_endian(bytes); Ok(PaymentId::U256(v)) }, - _ => Err(EncryptedDataError::IncorrectLength( - "Could not decrypt payment id due to incorrect length".to_string(), - )), + 67 => { + let v = + DualAddress::from_bytes(bytes).map_err(|e| EncryptedDataError::ByteArrayError(e.to_string()))?; + Ok(PaymentId::Address(v)) + }, + _ => Ok(PaymentId::Open(bytes.to_vec())), } } } @@ -134,9 +138,10 @@ impl Display for PaymentId { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { PaymentId::Zero => write!(f, "N/A"), - PaymentId::U32(v) => write!(f, "{}", v), PaymentId::U64(v) => write!(f, "{}", v), PaymentId::U256(v) => write!(f, "{}", v), + PaymentId::Address(v) => write!(f, "{}", v.to_emoji_string()), + PaymentId::Open(v) => write!(f, "byte vector of len: {}", v.len()), } } } @@ -223,17 +228,10 @@ impl EncryptedData { /// Parse encrypted data from a byte slice pub fn from_bytes(bytes: &[u8]) -> Result { - if !(bytes.len() == STATIC_ENCRYPTED_DATA_SIZE_TOTAL || - bytes.len() == STATIC_ENCRYPTED_DATA_SIZE_TOTAL + size_of::() || - bytes.len() == STATIC_ENCRYPTED_DATA_SIZE_TOTAL + size_of::() || - bytes.len() == STATIC_ENCRYPTED_DATA_SIZE_TOTAL + size_of::()) - { + if bytes.len() < STATIC_ENCRYPTED_DATA_SIZE_TOTAL { return Err(EncryptedDataError::IncorrectLength(format!( - "Expected {}, {}, {} or {} bytes, got {}", + "Expected bytes to be at least {}, got {}", STATIC_ENCRYPTED_DATA_SIZE_TOTAL, - STATIC_ENCRYPTED_DATA_SIZE_TOTAL + size_of::(), - STATIC_ENCRYPTED_DATA_SIZE_TOTAL + size_of::(), - STATIC_ENCRYPTED_DATA_SIZE_TOTAL + size_of::(), bytes.len() ))); } @@ -346,13 +344,14 @@ mod test { fn it_encrypts_and_decrypts_correctly() { for payment_id in [ PaymentId::Zero, - PaymentId::U32(1), - PaymentId::U32(3453636), PaymentId::U64(1), PaymentId::U64(156486946518564), PaymentId::U256( U256::from_dec_str("465465489789785458694894263185648978947864164681631").expect("Should not fail"), ), + PaymentId::Address(DualAddress::from_hex("2603bc3d05fb55446f18031feb5494d19d6c795fc93d6218c65a285c7a88fd03917c72e4a70cbabcc52ad79cb2ac170df4a29912ffb345f20b0f8ae5524c749b9425f0").unwrap()), + PaymentId::Open(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), + PaymentId::Open(vec![1;256]), ] { for (value, mask) in [ (0, PrivateKey::default()), @@ -365,7 +364,7 @@ mod test { let encryption_key = PrivateKey::random(&mut OsRng); let amount = MicroMinotari::from(value); let encrypted_data = - EncryptedData::encrypt_data(&encryption_key, &commitment, amount, &mask, payment_id).unwrap(); + EncryptedData::encrypt_data(&encryption_key, &commitment, amount, &mask, payment_id.clone()).unwrap(); let (decrypted_value, decrypted_mask, decrypted_payment_id) = EncryptedData::decrypt_data(&encryption_key, &commitment, &encrypted_data).unwrap(); assert_eq!(amount, decrypted_value); @@ -386,13 +385,14 @@ mod test { fn it_converts_correctly() { for payment_id in [ PaymentId::Zero, - PaymentId::U32(1), - PaymentId::U32(3453636), PaymentId::U64(1), PaymentId::U64(156486946518564), PaymentId::U256( U256::from_dec_str("465465489789785458694894263185648978947864164681631").expect("Should not fail"), ), + PaymentId::Address(DualAddress::from_hex("2603bc3d05fb55446f18031feb5494d19d6c795fc93d6218c65a285c7a88fd03917c72e4a70cbabcc52ad79cb2ac170df4a29912ffb345f20b0f8ae5524c749b9425f0").unwrap()), + PaymentId::Open(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), + PaymentId::Open(vec![1;256]), ] { for (value, mask) in [ (0, PrivateKey::default()), @@ -405,7 +405,7 @@ mod test { let encryption_key = PrivateKey::random(&mut OsRng); let amount = MicroMinotari::from(value); let encrypted_data = - EncryptedData::encrypt_data(&encryption_key, &commitment, amount, &mask, payment_id).unwrap(); + EncryptedData::encrypt_data(&encryption_key, &commitment, amount, &mask, payment_id.clone()).unwrap(); let bytes = encrypted_data.to_byte_vec(); let encrypted_data_from_bytes = EncryptedData::from_bytes(&bytes).unwrap(); assert_eq!(encrypted_data, encrypted_data_from_bytes); diff --git a/base_layer/core/src/validation/aggregate_body/aggregate_body_chain_validator.rs b/base_layer/core/src/validation/aggregate_body/aggregate_body_chain_validator.rs index 2c32dfad59..7032b5906a 100644 --- a/base_layer/core/src/validation/aggregate_body/aggregate_body_chain_validator.rs +++ b/base_layer/core/src/validation/aggregate_body/aggregate_body_chain_validator.rs @@ -262,7 +262,7 @@ pub fn check_outputs( body: &AggregateBody, ) -> Result<(), ValidationError> { let max_script_size = constants.max_script_byte_size(); - let max_encrypted_data_size = constants.max_encrypted_data_byte_size(); + let max_encrypted_data_size = constants.max_extra_encrypted_data_byte_size(); for output in body.outputs() { check_tari_script_byte_size(&output.script, max_script_size)?; check_tari_encrypted_data_byte_size(&output.encrypted_data, max_encrypted_data_size)?; diff --git a/base_layer/core/src/validation/aggregate_body/aggregate_body_internal_validator.rs b/base_layer/core/src/validation/aggregate_body/aggregate_body_internal_validator.rs index c4712aba41..92d1a086c9 100644 --- a/base_layer/core/src/validation/aggregate_body/aggregate_body_internal_validator.rs +++ b/base_layer/core/src/validation/aggregate_body/aggregate_body_internal_validator.rs @@ -114,7 +114,7 @@ impl AggregateBodyInternalConsistencyValidator { for output in body.outputs() { check_permitted_output_types(constants, output)?; check_script_size(output, constants.max_script_byte_size())?; - check_encrypted_data_byte_size(output, constants.max_encrypted_data_byte_size())?; + check_encrypted_data_byte_size(output, constants.max_extra_encrypted_data_byte_size())?; check_covenant_length(&output.covenant, constants.max_covenant_length())?; check_permitted_range_proof_types(constants, output)?; check_validator_node_registration_utxo(constants, output)?; diff --git a/base_layer/core/src/validation/block_body/test.rs b/base_layer/core/src/validation/block_body/test.rs index c5bfdce024..492a410aff 100644 --- a/base_layer/core/src/validation/block_body/test.rs +++ b/base_layer/core/src/validation/block_body/test.rs @@ -40,14 +40,18 @@ use crate::{ key_manager::{TariKeyId, TransactionKeyManagerBranch}, tari_amount::{uT, T}, test_helpers::schema_to_transaction, - transaction_components::{encrypted_data::PaymentId, EncryptedData, RangeProofType, TransactionError}, + transaction_components::{ + encrypted_data::{PaymentId, STATIC_ENCRYPTED_DATA_SIZE_TOTAL}, + EncryptedData, + RangeProofType, + TransactionError, + }, CoinbaseBuilder, CryptoFactories, }, txn_schema, validation::{BlockBodyValidator, ValidationError}, }; - async fn setup_with_rules(rules: ConsensusManager, check_rangeproof: bool) -> (TestBlockchain, BlockBodyFullValidator) { let blockchain = TestBlockchain::create(rules.clone()).await; let validator = BlockBodyFullValidator::new(rules, check_rangeproof); @@ -433,7 +437,7 @@ async fn it_limits_the_encrypted_data_byte_size() { let (txs, _) = schema_to_transaction(&[schema1], &blockchain.km).await; let mut txs = txs.into_iter().map(|t| Arc::try_unwrap(t).unwrap()).collect::>(); let mut outputs = txs[0].body.outputs().clone(); - outputs[0].encrypted_data = EncryptedData::from_vec_unsafe(vec![0; 33]); + outputs[0].encrypted_data = EncryptedData::from_vec_unsafe(vec![0; STATIC_ENCRYPTED_DATA_SIZE_TOTAL + 257]); txs[0].body = AggregateBody::new(txs[0].body.inputs().clone(), outputs, txs[0].body.kernels().clone()); let (block, _) = blockchain.create_next_tip(block_spec!("B", transactions: txs)).await; diff --git a/base_layer/core/src/validation/helpers.rs b/base_layer/core/src/validation/helpers.rs index ef349b325b..555740e268 100644 --- a/base_layer/core/src/validation/helpers.rs +++ b/base_layer/core/src/validation/helpers.rs @@ -237,7 +237,7 @@ pub fn check_tari_encrypted_data_byte_size( let encrypted_data_size = encrypted_data.as_bytes().len(); if encrypted_data_size > max_encrypted_data_size + STATIC_ENCRYPTED_DATA_SIZE_TOTAL { return Err(ValidationError::EncryptedDataExceedsMaxSize { - max_encrypted_data_size, + max_encrypted_data_size: max_encrypted_data_size + STATIC_ENCRYPTED_DATA_SIZE_TOTAL, actual_encrypted_data_size: encrypted_data_size, }); } diff --git a/base_layer/wallet/src/output_manager_service/storage/models.rs b/base_layer/wallet/src/output_manager_service/storage/models.rs index 1a00d0dd7b..45a144357d 100644 --- a/base_layer/wallet/src/output_manager_service/storage/models.rs +++ b/base_layer/wallet/src/output_manager_service/storage/models.rs @@ -69,7 +69,7 @@ impl DbWalletOutput { spent_in_tx_id: Option, ) -> Result { let tx_output = output.to_transaction_output(key_manager).await?; - let payment_id = output.payment_id; + let payment_id = output.payment_id.clone(); Ok(DbWalletOutput { hash: tx_output.hash(), commitment: tx_output.commitment, diff --git a/base_layer/wallet/src/output_manager_service/storage/sqlite_db/output_sql.rs b/base_layer/wallet/src/output_manager_service/storage/sqlite_db/output_sql.rs index 59ae6c14fe..6fed620602 100644 --- a/base_layer/wallet/src/output_manager_service/storage/sqlite_db/output_sql.rs +++ b/base_layer/wallet/src/output_manager_service/storage/sqlite_db/output_sql.rs @@ -776,7 +776,7 @@ impl OutputSql { Some(bytes) => Some(RangeProof::from_canonical_bytes(&bytes)?), None => None, }, - payment_id, + payment_id.clone(), ); let commitment = Commitment::from_vec(&self.commitment)?; diff --git a/base_layer/wallet/src/transaction_service/service.rs b/base_layer/wallet/src/transaction_service/service.rs index bab965fb92..3077898a53 100644 --- a/base_layer/wallet/src/transaction_service/service.rs +++ b/base_layer/wallet/src/transaction_service/service.rs @@ -1433,7 +1433,7 @@ where .encrypt_data_for_recovery( &self.resources.transaction_key_manager_service, Some(&encryption_key), - payment_id, + payment_id.clone(), ) .await? .with_input_data(inputs!(PublicKey::from_secret_key( diff --git a/base_layer/wallet_ffi/src/lib.rs b/base_layer/wallet_ffi/src/lib.rs index 64f3be5e4d..ef031f523b 100644 --- a/base_layer/wallet_ffi/src/lib.rs +++ b/base_layer/wallet_ffi/src/lib.rs @@ -6729,7 +6729,6 @@ pub unsafe extern "C" fn wallet_send_transaction( if one_sided { let payment_id = match payment_id { 0 => PaymentId::Zero, - x if x <= u64::from(u32::MAX) => PaymentId::U32(x.try_into().expect("number should fit into u32")), x => PaymentId::U64(x), }; match (*wallet).runtime.block_on(