From d5c8251ebec08a98fef46bbd00cb5df355219c1f Mon Sep 17 00:00:00 2001 From: Gianmarco Fraccaroli Date: Fri, 21 Jul 2023 21:45:58 +0200 Subject: [PATCH] client: refactor client methods --- apps/src/bin/namada-client/cli.rs | 69 +- apps/src/lib/cli.rs | 2 +- apps/src/lib/client/signing.rs | 4 +- apps/src/lib/client/tx.rs | 934 +++++++++--------- .../lib/node/ledger/shell/finalize_block.rs | 8 +- apps/src/lib/node/ledger/shell/mod.rs | 49 +- .../lib/node/ledger/shell/process_proposal.rs | 13 +- core/src/ledger/parameters/storage.rs | 17 +- core/src/ledger/storage_api/account.rs | 11 +- core/src/proto/types.rs | 27 +- core/src/types/account.rs | 16 +- core/src/types/transaction/wrapper.rs | 3 +- shared/src/ledger/args.rs | 2 +- shared/src/ledger/eth_bridge/bridge_pool.rs | 58 +- shared/src/ledger/ibc/vp/mod.rs | 165 ++-- .../ethereum_bridge/bridge_pool_vp.rs | 32 +- shared/src/ledger/signing.rs | 258 ++--- shared/src/ledger/tx.rs | 909 +++++++---------- shared/src/types/mod.rs | 1 + shared/src/vm/wasm/run.rs | 54 +- tests/src/native_vp/eth_bridge_pool.rs | 20 +- tests/src/vm_host_env/mod.rs | 507 +++++----- wasm/checksums.json | 40 +- wasm/wasm_source/src/tx_bond.rs | 20 +- .../src/tx_change_validator_commission.rs | 20 +- wasm/wasm_source/src/tx_unbond.rs | 19 +- wasm/wasm_source/src/tx_withdraw.rs | 19 +- wasm_for_tests/wasm_source/Cargo.toml | 1 - wasm_for_tests/wasm_source/Makefile | 1 - 29 files changed, 1597 insertions(+), 1682 deletions(-) diff --git a/apps/src/bin/namada-client/cli.rs b/apps/src/bin/namada-client/cli.rs index b07eab3691..5154e3c443 100644 --- a/apps/src/bin/namada-client/cli.rs +++ b/apps/src/bin/namada-client/cli.rs @@ -3,6 +3,7 @@ use color_eyre::eyre::{eyre, Report, Result}; use namada::ledger::eth_bridge::bridge_pool; use namada::ledger::rpc::wait_until_node_is_synched; +use namada::ledger::tx::dump_tx; use namada::ledger::{signing, tx as sdk_tx}; use namada::types::control_flow::ProceedOrElse; use namada_apps::cli; @@ -215,41 +216,51 @@ pub async fn main() -> Result<()> { .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); let tx_args = args.tx.clone(); - let (mut tx, addr, public_keys) = - bridge_pool::build_bridge_pool_tx( - &client, - &mut ctx.wallet, - args, - ) - .await - .unwrap(); - tx::submit_reveal_aux( + + let default_signer = + signing::signer_from_address(Some(args.sender.clone())); + let signing_data = signing::aux_signing_data( &client, - &mut ctx, - &tx_args, - addr.clone(), - &public_keys, - &mut tx, + &mut ctx.wallet, + &args.tx, + &args.sender, + default_signer, ) .await?; - let (account_public_keys_map, threshold) = - signing::aux_signing_data( - &client, - addr, - public_keys.clone(), - ) - .await; - signing::sign_tx( - &mut ctx.wallet, - &mut tx, - &tx_args, - &account_public_keys_map, - &public_keys, - threshold, + + let tx_builder = bridge_pool::build_bridge_pool_tx( + &client, + args.clone(), + signing_data.fee_payer.clone(), ) .await?; - sdk_tx::process_tx(&client, &mut ctx.wallet, &tx_args, tx) + + if args.tx.dump_tx { + dump_tx(&args.tx, tx_builder); + } else { + tx::submit_reveal_aux( + &client, + &mut ctx, + tx_args.clone(), + &args.sender, + ) + .await?; + + let tx_builder = signing::sign_tx( + &mut ctx.wallet, + &tx_args, + tx_builder, + signing_data, + )?; + + sdk_tx::process_tx( + &client, + &mut ctx.wallet, + &tx_args, + tx_builder, + ) .await?; + } } // Ledger queries Sub::QueryEpoch(QueryEpoch(mut args)) => { diff --git a/apps/src/lib/cli.rs b/apps/src/lib/cli.rs index 87e91e3057..688494179e 100644 --- a/apps/src/lib/cli.rs +++ b/apps/src/lib/cli.rs @@ -2657,7 +2657,7 @@ pub mod args { amount: self.amount, gas_amount: self.gas_amount, gas_payer: ctx.get(&self.gas_payer), - code_path: ctx.read_wasm(self.code_path), + code_path: self.code_path, } } } diff --git a/apps/src/lib/client/signing.rs b/apps/src/lib/client/signing.rs index 3c2a5d67fe..93ebe5f114 100644 --- a/apps/src/lib/client/signing.rs +++ b/apps/src/lib/client/signing.rs @@ -31,7 +31,7 @@ where /// signer. Return the given signing key or public key of the given signer if /// possible. If no explicit signer given, use the `default`. If no `default` /// is given, panics. -pub async fn tx_signer( +pub async fn tx_signers( client: &C, wallet: &mut Wallet, args: &args::Tx, @@ -42,7 +42,7 @@ where C::Error: std::fmt::Display, U: WalletUtils, { - namada::ledger::signing::tx_signer::(client, wallet, args, default) + namada::ledger::signing::tx_signers::(client, wallet, args, default) .await } diff --git a/apps/src/lib/client/tx.rs b/apps/src/lib/client/tx.rs index 2ff219e0b7..18c0a6c3b1 100644 --- a/apps/src/lib/client/tx.rs +++ b/apps/src/lib/client/tx.rs @@ -9,15 +9,13 @@ use async_trait::async_trait; use borsh::{BorshDeserialize, BorshSerialize}; use data_encoding::HEXLOWER_PERMISSIVE; use masp_proofs::prover::LocalTxProver; -use namada::core::types::account::AccountPublicKeysMap; use namada::ledger::governance::storage as gov_storage; use namada::ledger::rpc::{TxBroadcastData, TxResponse}; -use namada::ledger::signing::{find_pk, TxSigningKey}; +use namada::ledger::signing::find_pk; use namada::ledger::wallet::{Wallet, WalletUtils}; use namada::ledger::{masp, pos, signing, tx}; use namada::proof_of_stake::parameters::PosParams; -use namada::proto::{Code, Data, Section, Tx}; -use namada::types::address::Address; +use namada::types::address::{Address, ImplicitAddress}; use namada::types::dec::Dec; use namada::types::governance::{ OfflineProposal, OfflineVote, Proposal, ProposalVote, VoteType, @@ -27,7 +25,7 @@ use namada::types::storage::{Epoch, Key}; use namada::types::token; use namada::types::transaction::governance::{ProposalType, VoteProposalData}; use namada::types::transaction::pos::InitValidator; -use namada::types::transaction::TxType; +use namada::types::tx::TxBuilder; use super::rpc; use crate::cli::context::WalletAddress; @@ -44,48 +42,40 @@ use crate::wallet::{gen_validator_keys, read_and_confirm_encryption_password}; pub async fn submit_reveal_aux( client: &C, ctx: &mut Context, - args: &args::Tx, - addr: Option
, - public_keys: &[common::PublicKey], - tx: &mut Tx, + args: args::Tx, + address: &Address, ) -> Result<(), tx::Error> { - if let Some(Address::Implicit(_)) = addr { - for public_key in public_keys { - let reveal_pk = tx::build_reveal_pk( + if let Address::Implicit(ImplicitAddress(pkh)) = address { + let key = ctx + .wallet + .find_key_by_pkh(pkh, args.clone().password) + .map_err(|e| tx::Error::Other(e.to_string()))?; + let public_key = key.ref_to(); + + if tx::is_reveal_pk_needed::(client, address, args.force).await? { + let fee_payer = if let Some(fee_payer) = + args.clone().fee_payer.or(args.signing_keys.get(0).cloned()) + { + fee_payer + } else { + return Err(tx::Error::InvalidFeePayer); + }; + + let tx_builder = tx::build_reveal_pk::( client, - &mut ctx.wallet, - args::RevealPk { - tx: args.clone(), - public_key: public_key.clone(), - }, + &args, + address, + &public_key, + &fee_payer.ref_to(), ) .await?; - if let Some((mut rtx, _, public_keys)) = reveal_pk { - // Sign the reveal public key transaction with the fee payer - signing::sign_tx( - &mut ctx.wallet, - &mut rtx, - args, - &AccountPublicKeysMap::from_iter(public_keys.clone()), - &public_keys, - 1, - ) - .await?; - // Submit the reveal public key transaction first - tx::process_tx(client, &mut ctx.wallet, args, rtx).await?; - // Update the stateful PoW challenge of the outer transaction - #[cfg(not(feature = "mainnet"))] - signing::update_pow_challenge( - client, - args, - tx, - public_keys.get(0).unwrap(), - false, - ) - .await; - } + + let tx_builder = tx_builder.add_fee_payer(fee_payer); + + tx::process_tx(client, &mut ctx.wallet, &args, tx_builder).await?; } } + Ok(()) } @@ -98,29 +88,32 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, public_keys) = - tx::build_custom(client, &mut ctx.wallet, args.clone()).await?; - submit_reveal_aux( + let default_signer = signing::signer_from_address(None); + let signing_data = signing::aux_signing_data( client, - ctx, - &args.tx, - addr.clone(), - &public_keys, - &mut tx, - ) - .await?; - let (account_public_keys_map, threshold) = - signing::aux_signing_data(client, addr, public_keys.clone()).await; - signing::sign_tx( &mut ctx.wallet, - &mut tx, &args.tx, - &account_public_keys_map, - &public_keys, - threshold, + &args.owner, + default_signer, ) .await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + + let tx_builder = + tx::build_custom(client, &args, &signing_data.fee_payer).await?; + + if args.tx.dump_tx { + tx::dump_tx(&args.tx, tx_builder); + } else { + submit_reveal_aux(client, ctx, args.tx.clone(), &args.owner).await?; + let tx_builder = signing::sign_tx( + &mut ctx.wallet, + &args.tx, + tx_builder, + signing_data, + )?; + tx::process_tx(client, &mut ctx.wallet, &args.tx, tx_builder).await?; + } + Ok(()) } @@ -133,29 +126,32 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, public_keys) = - tx::build_update_account(client, &mut ctx.wallet, args.clone()).await?; - submit_reveal_aux( + let default_signer = signing::signer_from_address(Some(args.addr.clone())); + let signing_data = signing::aux_signing_data( client, - ctx, - &args.tx, - addr.clone(), - &public_keys, - &mut tx, - ) - .await?; - let (account_public_keys_map, threshold) = - signing::aux_signing_data(client, addr, public_keys.clone()).await; - signing::sign_tx( &mut ctx.wallet, - &mut tx, &args.tx, - &account_public_keys_map, - &public_keys, - threshold, + &args.addr, + default_signer, ) .await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + + let tx_builder = + tx::build_update_account(client, args.clone(), &signing_data.fee_payer) + .await?; + + if args.tx.dump_tx { + tx::dump_tx(&args.tx, tx_builder); + } else { + let tx_builder = signing::sign_tx( + &mut ctx.wallet, + &args.tx, + tx_builder, + signing_data, + )?; + tx::process_tx(client, &mut ctx.wallet, &args.tx, tx_builder).await?; + } + Ok(()) } @@ -168,30 +164,28 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, public_keys) = - tx::build_init_account(client, &mut ctx.wallet, args.clone()).await?; + let fee_payer = if let Some(fee_payer) = args.tx.fee_payer.clone().or(args + .tx + .signing_keys + .get(0) + .cloned()) + { + fee_payer + } else { + return Err(tx::Error::InvalidFeePayer); + }; + + let tx_builder = + tx::build_init_account(client, args.clone(), &fee_payer.ref_to()) + .await?; + + if args.tx.dump_tx { + tx::dump_tx(&args.tx, tx_builder); + } else { + let tx_builder = tx_builder.add_fee_payer(fee_payer); + tx::process_tx(client, &mut ctx.wallet, &args.tx, tx_builder).await?; + } - submit_reveal_aux( - client, - ctx, - &args.tx, - addr.clone(), - &public_keys, - &mut tx, - ) - .await?; - let (account_public_keys_map, threshold) = - signing::aux_signing_data(client, addr, public_keys.clone()).await; - signing::sign_tx( - &mut ctx.wallet, - &mut tx, - &args.tx, - &account_public_keys_map, - &public_keys, - threshold, - ) - .await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; Ok(()) } @@ -378,10 +372,12 @@ where .await .unwrap(); - let mut tx = Tx::new(TxType::Raw); - let extra = tx.add_section(Section::ExtraData(Code::from_hash( - validator_vp_code_hash, - ))); + let chain_id = tx_args.chain_id.clone().unwrap(); + let tx_builder = TxBuilder::new(chain_id, tx_args.expiration); + + let (tx_builder, extra_section_hash) = + tx_builder.add_extra_section_from_hash(validator_vp_code_hash); + let data = InitValidator { account_keys, threshold, @@ -394,109 +390,109 @@ where dkg_key, commission_rate, max_commission_rate_change, - validator_vp_code_hash: extra.get_hash(), + validator_vp_code_hash: extra_section_hash, }; - let data = data.try_to_vec().expect("Encoding tx data shouldn't fail"); - tx.header.chain_id = tx_args.chain_id.clone().unwrap(); - tx.header.expiration = tx_args.expiration; - tx.set_data(Data::new(data)); - tx.set_code(Code::from_hash(tx_code_hash)); - let (mut tx, addr, public_keys) = tx::prepare_tx( + let tx_builder = tx_builder.add_code_from_hash(tx_code_hash).add_data(data); + + let fee_payer = if let Some(fee_payer) = tx_args + .fee_payer + .clone() + .or(tx_args.signing_keys.get(0).cloned()) + { + fee_payer + } else { + return Err(tx::Error::InvalidFeePayer); + }; + + let tx_builder = tx::prepare_tx( client, - &mut ctx.wallet, &tx_args, - tx, - None, - TxSigningKey::None, + tx_builder, + fee_payer.ref_to(), #[cfg(not(feature = "mainnet"))] false, ) .await?; - submit_reveal_aux( - client, - &mut ctx, - &tx_args, - addr.clone(), - &public_keys, - &mut tx, - ) - .await?; - let (account_public_keys_map, threshold) = - signing::aux_signing_data(client, addr, public_keys.clone()).await; - signing::sign_tx( - &mut ctx.wallet, - &mut tx, - &tx_args, - &account_public_keys_map, - &public_keys, - threshold, - ) - .await?; - let result = tx::process_tx(client, &mut ctx.wallet, &tx_args, tx) - .await? - .initialized_accounts(); - - if !tx_args.dry_run { - let (validator_address_alias, validator_address) = match &result[..] { - // There should be 1 account for the validator itself - [validator_address] => { - if let Some(alias) = ctx.wallet.find_alias(validator_address) { - (alias.clone(), validator_address.clone()) - } else { + + if tx_args.dump_tx { + tx::dump_tx(&tx_args, tx_builder); + } else { + let tx_builder = tx_builder.add_fee_payer(fee_payer); + + let result = + tx::process_tx(client, &mut ctx.wallet, &tx_args, tx_builder) + .await? + .initialized_accounts(); + + if !tx_args.dry_run { + let (validator_address_alias, validator_address) = match &result[..] + { + // There should be 1 account for the validator itself + [validator_address] => { + if let Some(alias) = + ctx.wallet.find_alias(validator_address) + { + (alias.clone(), validator_address.clone()) + } else { + eprintln!("Expected one account to be created"); + safe_exit(1) + } + } + _ => { eprintln!("Expected one account to be created"); safe_exit(1) } - } - _ => { - eprintln!("Expected one account to be created"); - safe_exit(1) - } - }; - // add validator address and keys to the wallet - ctx.wallet - .add_validator_data(validator_address, validator_keys); - crate::wallet::save(&ctx.wallet) - .unwrap_or_else(|err| eprintln!("{}", err)); - - let tendermint_home = ctx.config.ledger.cometbft_dir(); - tendermint_node::write_validator_key(&tendermint_home, &consensus_key); - tendermint_node::write_validator_state(tendermint_home); - - // Write Namada config stuff or figure out how to do the above - // tendermint_node things two epochs in the future!!! - ctx.config.ledger.shell.tendermint_mode = TendermintMode::Validator; - ctx.config - .write( - &ctx.config.ledger.shell.base_dir, - &ctx.config.ledger.chain_id, - true, - ) - .unwrap(); + }; + // add validator address and keys to the wallet + ctx.wallet + .add_validator_data(validator_address, validator_keys); + crate::wallet::save(&ctx.wallet) + .unwrap_or_else(|err| eprintln!("{}", err)); + + let tendermint_home = ctx.config.ledger.cometbft_dir(); + tendermint_node::write_validator_key( + &tendermint_home, + &consensus_key, + ); + tendermint_node::write_validator_state(tendermint_home); + + // Write Namada config stuff or figure out how to do the above + // tendermint_node things two epochs in the future!!! + ctx.config.ledger.shell.tendermint_mode = TendermintMode::Validator; + ctx.config + .write( + &ctx.config.ledger.shell.base_dir, + &ctx.config.ledger.chain_id, + true, + ) + .unwrap(); - let key = pos::params_key(); - let pos_params = rpc::query_storage_value::(client, &key) - .await - .expect("Pos parameter should be defined."); + let key = pos::params_key(); + let pos_params = + rpc::query_storage_value::(client, &key) + .await + .expect("Pos parameter should be defined."); - println!(); - println!( - "The validator's addresses and keys were stored in the wallet:" - ); - println!(" Validator address \"{}\"", validator_address_alias); - println!(" Validator account key \"{}\"", validator_key_alias); - println!(" Consensus key \"{}\"", consensus_key_alias); - println!( - "The ledger node has been setup to use this validator's address \ - and consensus key." - ); - println!( - "Your validator will be active in {} epochs. Be sure to restart \ - your node for the changes to take effect!", - pos_params.pipeline_len - ); - } else { - println!("Transaction dry run. No addresses have been saved."); + println!(); + println!( + "The validator's addresses and keys were stored in the wallet:" + ); + println!(" Validator address \"{}\"", validator_address_alias); + println!(" Validator account key \"{}\"", validator_key_alias); + println!(" Consensus key \"{}\"", consensus_key_alias); + println!( + "The ledger node has been setup to use this validator's \ + address and consensus key." + ); + println!( + "Your validator will be active in {} epochs. Be sure to \ + restart your node for the changes to take effect!", + pos_params.pipeline_len + ); + } else { + println!("Transaction dry run. No addresses have been saved."); + } } Ok(()) } @@ -617,56 +613,71 @@ pub async fn submit_transfer( args: args::TxTransfer, ) -> Result<(), tx::Error> { for _ in 0..2 { - let arg = args.clone(); - let (mut tx, addr, public_keys, tx_epoch, _isf) = - tx::build_transfer(client, &mut ctx.wallet, &mut ctx.shielded, arg) - .await?; - submit_reveal_aux( + let default_signer = + signing::signer_from_address(Some(args.source.effective_address())); + let signing_data = signing::aux_signing_data( client, - &mut ctx, + &mut ctx.wallet, &args.tx, - addr.clone(), - &public_keys, - &mut tx, + &args.source.effective_address(), + default_signer, ) .await?; - let (account_public_keys_map, threshold) = - signing::aux_signing_data(client, addr, public_keys.clone()).await; - signing::sign_tx( - &mut ctx.wallet, - &mut tx, - &args.tx, - &account_public_keys_map, - &public_keys, - threshold, + + let arg = args.clone(); + let (tx_builder, tx_epoch) = tx::build_transfer( + client, + &mut ctx.shielded, + arg, + &signing_data.fee_payer, ) .await?; - let result = - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; - // Query the epoch in which the transaction was probably submitted - let submission_epoch = rpc::query_and_print_epoch(client).await; - - match result { - ProcessTxResponse::Applied(resp) if - // If a transaction is shielded - tx_epoch.is_some() && - // And it is rejected by a VP - resp.code == 1.to_string() && - // And the its submission epoch doesn't match construction epoch - tx_epoch.unwrap() != submission_epoch => - { - // Then we probably straddled an epoch boundary. Let's retry... - eprintln!( - "MASP transaction rejected and this may be due to the \ - epoch changing. Attempting to resubmit transaction.", - ); - continue; - }, - // Otherwise either the transaction was successful or it will not - // benefit from resubmission - _ => break, + + if args.tx.dump_tx { + tx::dump_tx(&args.tx, tx_builder); + } else { + submit_reveal_aux( + client, + &mut ctx, + args.tx.clone(), + &args.source.effective_address(), + ) + .await?; + let tx_builder = signing::sign_tx( + &mut ctx.wallet, + &args.tx, + tx_builder, + signing_data, + )?; + let result = + tx::process_tx(client, &mut ctx.wallet, &args.tx, tx_builder) + .await?; + + let submission_epoch = rpc::query_and_print_epoch(client).await; + + match result { + ProcessTxResponse::Applied(resp) if + // If a transaction is shielded + tx_epoch.is_some() && + // And it is rejected by a VP + resp.code == 1.to_string() && + // And its submission epoch doesn't match construction epoch + tx_epoch.unwrap() != submission_epoch => + { + // Then we probably straddled an epoch boundary. Let's retry... + eprintln!( + "MASP transaction rejected and this may be due to the \ + epoch changing. Attempting to resubmit transaction.", + ); + continue; + }, + // Otherwise either the transaction was successful or it will not + // benefit from resubmission + _ => break, + } } } + Ok(()) } @@ -679,29 +690,35 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, public_keys) = - tx::build_ibc_transfer(client, &mut ctx.wallet, args.clone()).await?; - submit_reveal_aux( + let default_signer = + signing::signer_from_address(Some(args.source.clone())); + let signing_data = signing::aux_signing_data( client, - &mut ctx, - &args.tx, - addr.clone(), - &public_keys, - &mut tx, - ) - .await?; - let (account_public_keys_map, threshold) = - signing::aux_signing_data(client, addr, public_keys.clone()).await; - signing::sign_tx( &mut ctx.wallet, - &mut tx, &args.tx, - &account_public_keys_map, - &public_keys, - threshold, + &args.source, + default_signer, ) .await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + + let tx_builder = + tx::build_ibc_transfer(client, args.clone(), &signing_data.fee_payer) + .await?; + + if args.tx.dump_tx { + tx::dump_tx(&args.tx, tx_builder); + } else { + submit_reveal_aux(client, &mut ctx, args.tx.clone(), &args.source) + .await?; + let tx_builder = signing::sign_tx( + &mut ctx.wallet, + &args.tx, + tx_builder, + signing_data, + )?; + tx::process_tx(client, &mut ctx.wallet, &args.tx, tx_builder).await?; + } + Ok(()) } @@ -838,66 +855,69 @@ where safe_exit(1); } - let mut tx = Tx::new(TxType::Raw); let tx_code_hash = query_wasm_code_hash(client, args::TX_INIT_PROPOSAL) .await .unwrap(); - tx.header.chain_id = ctx.config.ledger.chain_id.clone(); - tx.header.expiration = args.tx.expiration; - // Put the content of this proposal into an extra section - { - let content_sec = tx.add_section(Section::ExtraData(Code::new( - init_proposal_content, - ))); - let content_sec_hash = content_sec.get_hash(); - init_proposal_data.content = content_sec_hash; - } - // Put any proposal code into an extra section - if let Some(init_proposal_code) = init_proposal_code { - let code_sec = tx - .add_section(Section::ExtraData(Code::new(init_proposal_code))); - let code_sec_hash = code_sec.get_hash(); - init_proposal_data.r#type = - ProposalType::Default(Some(code_sec_hash)); - } - let data = init_proposal_data - .try_to_vec() - .expect("Encoding proposal data shouldn't fail"); - tx.set_data(Data::new(data)); - tx.set_code(Code::from_hash(tx_code_hash)); - let (mut tx, addr, public_keys) = tx::prepare_tx( + let default_signer = signing::signer_from_address(Some(signer.clone())); + let signing_data = signing::aux_signing_data( client, &mut ctx.wallet, &args.tx, - tx, - Some(signer.clone()), - TxSigningKey::WalletAddress(signer), - #[cfg(not(feature = "mainnet"))] - false, + &signer, + default_signer, ) .await?; - submit_reveal_aux( + + let chain_id = args.tx.chain_id.clone().unwrap(); + let tx_builder = TxBuilder::new(chain_id, args.tx.expiration); + + // Put any proposal content into an extra section + let (tx_builder, extra_section_hash) = + tx_builder.add_extra_section(init_proposal_content); + init_proposal_data.content = extra_section_hash; + + // Put any proposal code into an extra section + let tx_builder = if let Some(init_proposal_code) = init_proposal_code { + let (tx_builder, extra_section_hash) = + tx_builder.add_extra_section(init_proposal_code); + init_proposal_data.r#type = + ProposalType::Default(Some(extra_section_hash)); + tx_builder + } else { + tx_builder + }; + + let tx_builder = tx_builder + .add_code_from_hash(tx_code_hash) + .add_data(init_proposal_data); + + let tx_builder = tx::prepare_tx( client, - &mut ctx, - &args.tx, - addr.clone(), - &public_keys, - &mut tx, - ) - .await?; - let (account_public_keys_map, threshold) = - signing::aux_signing_data(client, addr, public_keys.clone()).await; - signing::sign_tx( - &mut ctx.wallet, - &mut tx, &args.tx, - &account_public_keys_map, - &public_keys, - threshold, + tx_builder, + signing_data.fee_payer.clone(), + #[cfg(not(feature = "mainnet"))] + false, ) .await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + + if args.tx.dump_tx { + tx::dump_tx(&args.tx, tx_builder); + } else { + submit_reveal_aux(client, &mut ctx, args.tx.clone(), &signer) + .await?; + + let tx_builder = signing::sign_tx( + &mut ctx.wallet, + &args.tx, + tx_builder, + signing_data, + )?; + + tx::process_tx(client, &mut ctx.wallet, &args.tx, tx_builder) + .await?; + } Ok(()) } @@ -1127,61 +1147,62 @@ where delegations: delegations.into_iter().collect(), }; - let chain_id = args.tx.chain_id.clone().unwrap(); - let expiration = args.tx.expiration; - let data = tx_data - .try_to_vec() - .expect("Encoding proposal data shouldn't fail"); - let tx_code_hash = query_wasm_code_hash( client, args.tx_code_path.to_str().unwrap(), ) .await .unwrap(); - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = chain_id; - tx.header.expiration = expiration; - tx.set_data(Data::new(data)); - tx.set_code(Code::from_hash(tx_code_hash)); - let (mut tx, addr, public_keys) = tx::prepare_tx( + let default_signer = signing::signer_from_address(Some( + args.voter_address.clone(), + )); + let signing_data = signing::aux_signing_data( client, &mut ctx.wallet, &args.tx, - tx, - Some(args.voter_address.clone()), - TxSigningKey::WalletAddress(args.voter_address.clone()), - #[cfg(not(feature = "mainnet"))] - false, + &args.voter_address, + default_signer, ) .await?; - submit_reveal_aux( + + let chain_id = args.tx.chain_id.clone().unwrap(); + let tx_builder = TxBuilder::new(chain_id, args.tx.expiration); + + let tx_builder = tx_builder + .add_code_from_hash(tx_code_hash) + .add_data(tx_data); + + let tx_builder = tx::prepare_tx( client, - &mut ctx, &args.tx, - addr.clone(), - &public_keys, - &mut tx, + tx_builder, + signing_data.fee_payer.clone(), + #[cfg(not(feature = "mainnet"))] + false, ) .await?; - let (account_public_keys_map, threshold) = - signing::aux_signing_data( + + if args.tx.dump_tx { + tx::dump_tx(&args.tx, tx_builder); + } else { + // no need to releal pk since people who an vote on + // governane proposal must be enstablished addresses + + let tx_builder = signing::sign_tx( + &mut ctx.wallet, + &args.tx, + tx_builder, + signing_data, + )?; + tx::process_tx( client, - addr, - public_keys.clone(), + &mut ctx.wallet, + &args.tx, + tx_builder, ) - .await; - signing::sign_tx( - &mut ctx.wallet, - &mut tx, - &args.tx, - &account_public_keys_map, - &public_keys, - threshold, - ) - .await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + .await?; + } Ok(()) } None => { @@ -1204,22 +1225,8 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let reveal_tx = - tx::build_reveal_pk(client, &mut ctx.wallet, args.clone()).await?; - if let Some((mut tx, _, public_keys)) = reveal_tx { - let (account_pks_index_map, threshold) = - signing::aux_signing_data(client, None, public_keys.clone()).await; - signing::sign_tx( - &mut ctx.wallet, - &mut tx, - &args.tx, - &account_pks_index_map, - &public_keys, - threshold, - ) - .await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; - } + submit_reveal_aux(client, ctx, args.tx, &(&args.public_key).into()).await?; + Ok(()) } @@ -1290,29 +1297,38 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, public_keys) = - tx::build_bond::(client, &mut ctx.wallet, args.clone()).await?; - submit_reveal_aux( + let default_address = args.source.clone().unwrap_or(args.validator.clone()); + let default_signer = + signing::signer_from_address(Some(default_address.clone())); + let signing_data = signing::aux_signing_data( client, - ctx, - &args.tx, - addr.clone(), - &public_keys, - &mut tx, - ) - .await?; - let (account_public_keys_map, threshold) = - signing::aux_signing_data(client, addr, public_keys.clone()).await; - signing::sign_tx( &mut ctx.wallet, - &mut tx, &args.tx, - &account_public_keys_map, - &public_keys, - threshold, + &default_address, + default_signer, ) .await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + + let tx_builder = + tx::build_bond::(client, args.clone(), &signing_data.fee_payer) + .await?; + + if args.tx.dump_tx { + tx::dump_tx(&args.tx, tx_builder); + } else { + submit_reveal_aux(client, ctx, args.tx.clone(), &default_address) + .await?; + + let tx_builder = signing::sign_tx( + &mut ctx.wallet, + &args.tx, + tx_builder, + signing_data, + )?; + + tx::process_tx(client, &mut ctx.wallet, &args.tx, tx_builder).await?; + } + Ok(()) } @@ -1325,30 +1341,41 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, public_keys, latest_withdrawal_pre) = - tx::build_unbond(client, &mut ctx.wallet, args.clone()).await?; - submit_reveal_aux( + let default_address = args.source.clone().unwrap_or(args.validator.clone()); + let default_signer = + signing::signer_from_address(Some(default_address.clone())); + let signing_data = signing::aux_signing_data( client, - ctx, + &mut ctx.wallet, &args.tx, - addr.clone(), - &public_keys, - &mut tx, + &default_address, + default_signer, ) .await?; - let (account_public_keys_map, threshold) = - signing::aux_signing_data(client, addr, public_keys.clone()).await; - signing::sign_tx( + + let (tx_builder, latest_withdrawal_pre) = tx::build_unbond( + client, &mut ctx.wallet, - &mut tx, - &args.tx, - &account_public_keys_map, - &public_keys, - threshold, + args.clone(), + &signing_data.fee_payer, ) .await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; - tx::query_unbonds(client, args.clone(), latest_withdrawal_pre).await?; + + if args.tx.dump_tx { + tx::dump_tx(&args.tx, tx_builder); + } else { + let tx_builder = signing::sign_tx( + &mut ctx.wallet, + &args.tx, + tx_builder, + signing_data, + )?; + + tx::process_tx(client, &mut ctx.wallet, &args.tx, tx_builder).await?; + + tx::query_unbonds(client, args.clone(), latest_withdrawal_pre).await?; + } + Ok(()) } @@ -1361,29 +1388,35 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, public_keys) = - tx::build_withdraw(client, &mut ctx.wallet, args.clone()).await?; - submit_reveal_aux( + let default_address = args.source.clone().unwrap_or(args.validator.clone()); + let default_signer = + signing::signer_from_address(Some(default_address.clone())); + let signing_data = signing::aux_signing_data( client, - &mut ctx, - &args.tx, - addr.clone(), - &public_keys, - &mut tx, - ) - .await?; - let (account_public_keys_map, threshold) = - signing::aux_signing_data(client, addr, public_keys.clone()).await; - signing::sign_tx( &mut ctx.wallet, - &mut tx, &args.tx, - &account_public_keys_map, - &public_keys, - threshold, + &default_address, + default_signer, ) .await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + + let tx_builder = + tx::build_withdraw(client, args.clone(), &signing_data.fee_payer) + .await?; + + if args.tx.dump_tx { + tx::dump_tx(&args.tx, tx_builder); + } else { + let tx_builder = signing::sign_tx( + &mut ctx.wallet, + &args.tx, + tx_builder, + signing_data, + )?; + + tx::process_tx(client, &mut ctx.wallet, &args.tx, tx_builder).await?; + } + Ok(()) } @@ -1396,31 +1429,37 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let arg = args.clone(); - let (mut tx, addr, public_keys) = - tx::build_validator_commission_change(client, &mut ctx.wallet, arg) - .await?; - submit_reveal_aux( + let default_signer = + signing::signer_from_address(Some(args.validator.clone())); + let signing_data = signing::aux_signing_data( client, - &mut ctx, + &mut ctx.wallet, &args.tx, - addr.clone(), - &public_keys, - &mut tx, + &args.validator, + default_signer, ) .await?; - let (account_public_keys_map, threshold) = - signing::aux_signing_data(client, addr, public_keys.clone()).await; - signing::sign_tx( - &mut ctx.wallet, - &mut tx, - &args.tx, - &account_public_keys_map, - &public_keys, - threshold, + + let tx_builder = tx::build_validator_commission_change( + client, + args.clone(), + &signing_data.fee_payer, ) .await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + + if args.tx.dump_tx { + tx::dump_tx(&args.tx, tx_builder); + } else { + let tx_builder = signing::sign_tx( + &mut ctx.wallet, + &args.tx, + tx_builder, + signing_data, + )?; + + tx::process_tx(client, &mut ctx.wallet, &args.tx, tx_builder).await?; + } + Ok(()) } @@ -1435,30 +1474,37 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, public_keys) = - tx::build_unjail_validator(client, &mut ctx.wallet, args.clone()) - .await?; - submit_reveal_aux( + let default_signer = + signing::signer_from_address(Some(args.validator.clone())); + let signing_data = signing::aux_signing_data( client, - &mut ctx, + &mut ctx.wallet, &args.tx, - addr.clone(), - &public_keys, - &mut tx, + &args.validator, + default_signer, ) .await?; - let (account_public_keys_map, threshold) = - signing::aux_signing_data(client, addr, public_keys.clone()).await; - signing::sign_tx( - &mut ctx.wallet, - &mut tx, - &args.tx, - &account_public_keys_map, - &public_keys, - threshold, + + let tx_builder = tx::build_unjail_validator( + client, + args.clone(), + &signing_data.fee_payer, ) .await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + + if args.tx.dump_tx { + tx::dump_tx(&args.tx, tx_builder); + } else { + let tx_builder = signing::sign_tx( + &mut ctx.wallet, + &args.tx, + tx_builder, + signing_data, + )?; + + tx::process_tx(client, &mut ctx.wallet, &args.tx, tx_builder).await?; + } + Ok(()) } diff --git a/apps/src/lib/node/ledger/shell/finalize_block.rs b/apps/src/lib/node/ledger/shell/finalize_block.rs index 3af8ab9e3f..3f11f008b8 100644 --- a/apps/src/lib/node/ledger/shell/finalize_block.rs +++ b/apps/src/lib/node/ledger/shell/finalize_block.rs @@ -1011,6 +1011,7 @@ mod test_finalize_block { }; use namada::types::transaction::protocol::EthereumTxData; use namada::types::transaction::{Fee, WrapperTx, MIN_FEE_AMOUNT}; + use namada::types::tx::TxBuilder; use namada::types::uint::Uint; use namada::types::vote_extensions::ethereum_events; use namada_test_utils::TestWasms; @@ -3496,8 +3497,11 @@ mod test_finalize_block { .wl_storage .write(&proposal_execution_key, 0u64) .expect("Test failed."); - let mut tx = Tx::new(TxType::Raw); - tx.set_data(Data::new(0u64.try_to_vec().expect("Test failed"))); + let tx_builder = TxBuilder::new(shell.chain_id.clone(), None); + let tx = tx_builder + .add_code_from_hash(Hash::default()) + .add_data(0u64) + .build(); let new_min_confirmations = MinimumConfirmations::from(unsafe { NonZeroU64::new_unchecked(42) }); diff --git a/apps/src/lib/node/ledger/shell/mod.rs b/apps/src/lib/node/ledger/shell/mod.rs index 428a6f14df..5fd505e344 100644 --- a/apps/src/lib/node/ledger/shell/mod.rs +++ b/apps/src/lib/node/ledger/shell/mod.rs @@ -2053,6 +2053,7 @@ mod test_mempool_validate { use namada::proof_of_stake::Epoch; use namada::proto::{Code, Data, Section, Signature, Tx}; use namada::types::transaction::{Fee, WrapperTx}; + use namada::types::tx::TxBuilder; use super::*; @@ -2145,10 +2146,10 @@ mod test_mempool_validate { fn test_wrong_tx_type() { let (shell, _recv, _, _) = test_utils::setup(); - // Test Raw TxType - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = shell.chain_id.clone(); - tx.set_code(Code::new("wasm_code".as_bytes().to_owned())); + let tx_builder = TxBuilder::new(shell.chain_id.clone(), None); + let tx = tx_builder + .add_code("wasm_code".as_bytes().to_owned()) + .build(); let result = shell.mempool_validate( tx.to_bytes().as_ref(), @@ -2277,18 +2278,12 @@ mod test_mempool_validate { let keypair = super::test_utils::gen_keypair(); let wrong_chain_id = ChainId("Wrong chain id".to_string()); - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = wrong_chain_id.clone(); - tx.set_code(Code::new("wasm_code".as_bytes().to_owned())); - tx.set_data(Data::new("transaction data".as_bytes().to_owned())); - tx.add_section(Section::Signature(Signature::new( - vec![ - tx.header_hash(), - tx.sections[0].get_hash(), - tx.sections[1].get_hash(), - ], - &keypair, - ))); + let tx_builder = TxBuilder::new(wrong_chain_id.clone(), None); + let tx = tx_builder + .add_code("wasm_code".as_bytes().to_owned()) + .add_data("transaction data".as_bytes().to_owned()) + .add_fee_payer(keypair) + .build(); let result = shell.mempool_validate( tx.to_bytes().as_ref(), @@ -2312,19 +2307,15 @@ mod test_mempool_validate { let keypair = super::test_utils::gen_keypair(); - let mut tx = Tx::new(TxType::Raw); - tx.header.expiration = Some(DateTimeUtc::default()); - tx.header.chain_id = shell.chain_id.clone(); - tx.set_code(Code::new("wasm_code".as_bytes().to_owned())); - tx.set_data(Data::new("transaction data".as_bytes().to_owned())); - tx.add_section(Section::Signature(Signature::new( - vec![ - tx.header_hash(), - tx.sections[0].get_hash(), - tx.sections[1].get_hash(), - ], - &keypair, - ))); + let tx_builder = TxBuilder::new( + shell.chain_id.clone(), + Some(DateTimeUtc::default()), + ); + let tx = tx_builder + .add_code("wasm_code".as_bytes().to_owned()) + .add_data("transaction data".as_bytes().to_owned()) + .add_fee_payer(keypair) + .build(); let result = shell.mempool_validate( tx.to_bytes().as_ref(), diff --git a/apps/src/lib/node/ledger/shell/process_proposal.rs b/apps/src/lib/node/ledger/shell/process_proposal.rs index 3a5b4935db..9b9488eacb 100644 --- a/apps/src/lib/node/ledger/shell/process_proposal.rs +++ b/apps/src/lib/node/ledger/shell/process_proposal.rs @@ -964,6 +964,7 @@ mod test_process_proposal { use namada::types::token::Amount; use namada::types::transaction::protocol::EthereumTxData; use namada::types::transaction::{Fee, WrapperTx, MIN_FEE}; + use namada::types::tx::TxBuilder; #[cfg(feature = "abcipp")] use namada::types::vote_extensions::bridge_pool_roots::MultiSignedVext; #[cfg(feature = "abcipp")] @@ -2027,10 +2028,14 @@ mod test_process_proposal { fn test_raw_tx_rejected() { let (mut shell, _recv, _, _) = test_utils::setup_at_height(3u64); - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = shell.chain_id.clone(); - tx.set_code(Code::new("wasm_code".as_bytes().to_owned())); - tx.set_data(Data::new("transaction data".as_bytes().to_owned())); + let keypair = crate::wallet::defaults::daewon_keypair(); + + let tx_builder = TxBuilder::new(shell.chain_id.clone(), None); + let tx = tx_builder + .add_code("wasm_code".as_bytes().to_owned()) + .add_data("transaction data".as_bytes().to_owned()) + .add_fee_payer(keypair) + .build(); let response = { let request = ProcessProposal { diff --git a/core/src/ledger/parameters/storage.rs b/core/src/ledger/parameters/storage.rs index cdb484dd32..d32b1d221f 100644 --- a/core/src/ledger/parameters/storage.rs +++ b/core/src/ledger/parameters/storage.rs @@ -120,14 +120,6 @@ pub fn is_max_proposal_bytes_key(key: &Key) -> bool { is_max_proposal_bytes_key_at_addr(key, &ADDRESS) } -/// Returns if the key is the max signature per transacton key -pub fn is_max_signatures_per_transaction_key(key: &Key) -> bool { - matches!(&key.segments[..], [ - DbKeySeg::AddressSeg(addr), - DbKeySeg::StringSeg(max_signatures_per_transaction), - ] if addr == &ADDRESS && max_signatures_per_transaction == Keys::VALUES.max_signatures_per_transaction) -} - /// Storage key used for epoch parameter. pub fn get_epoch_duration_storage_key() -> Key { get_epoch_duration_key_at_addr(ADDRESS) @@ -195,12 +187,5 @@ pub fn get_wrapper_tx_fees_key() -> Key { /// Storage key used for the max signatures per transaction key pub fn get_max_signatures_per_transaction_key() -> Key { - Key { - segments: vec![ - DbKeySeg::AddressSeg(ADDRESS), - DbKeySeg::StringSeg( - Keys::VALUES.max_signatures_per_transaction.to_string(), - ), - ], - } + get_max_signatures_per_transaction_key_at_addr(ADDRESS) } diff --git a/core/src/ledger/storage_api/account.rs b/core/src/ledger/storage_api/account.rs index 69d348710d..4896de635f 100644 --- a/core/src/ledger/storage_api/account.rs +++ b/core/src/ledger/storage_api/account.rs @@ -33,7 +33,7 @@ where storage.read(&threshold_key) } -/// Get the public keys index map associated with an account +/// Get the public keys associated with an account pub fn public_keys( storage: &S, owner: &Address, @@ -70,8 +70,13 @@ pub fn exists(storage: &S, owner: &Address) -> Result where S: StorageRead, { - let vp_key = Key::validity_predicate(owner); - storage.has_key(&vp_key) + match owner { + Address::Established(_) => { + let vp_key = Key::validity_predicate(owner); + storage.has_key(&vp_key) + } + Address::Implicit(_) | Address::Internal(_) => Ok(true), + } } /// Set public key at specific index diff --git a/core/src/proto/types.rs b/core/src/proto/types.rs index be20621b43..8246dd8a13 100644 --- a/core/src/proto/types.rs +++ b/core/src/proto/types.rs @@ -2,11 +2,8 @@ use std::borrow::Cow; use std::cmp::Ordering; use std::collections::{BTreeSet, HashMap, HashSet}; use std::convert::TryFrom; -use std::env; -use std::fs::File; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; -use std::path::PathBuf; #[cfg(feature = "ferveo-tpke")] use ark_ec::AffineCurve; @@ -14,6 +11,7 @@ use ark_ec::AffineCurve; use ark_ec::PairingEngine; use borsh::schema::{Declaration, Definition}; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; +use data_encoding::HEXUPPER; use masp_primitives::transaction::builder::Builder; use masp_primitives::transaction::components::sapling::builder::SaplingMetadata; use masp_primitives::transaction::Transaction; @@ -869,7 +867,6 @@ impl borsh::BorshSchema for MaspBuilder { Serialize, Deserialize, )] -#[allow(clippy::large_enum_variant)] pub enum Section { /// Transaction data that needs to be sent to hardware wallets Data(Data), @@ -1147,22 +1144,12 @@ impl Tx { } } - /// Dump to file - // TODO: refactor - pub fn dump(&self, path: Option) -> Result { - let path = path - .unwrap_or(env::current_dir().expect( - "Should be able to get the current working directory.", - )); - let tx_filename = format!("{}.tx", self.header_hash()); - let tx_filename_clone_error = tx_filename.clone(); - let tx_filename_clone_ok = tx_filename.clone(); - let out = File::create(path.join(tx_filename)).unwrap(); - serde_json::to_writer_pretty(out, &self) - .map_err(|_| { - Error::InvalidJSONDeserialization(tx_filename_clone_error) - }) - .map(|_| path.join(tx_filename_clone_ok)) + /// Dump tx to hex string + pub fn serialize(&self) -> String { + let tx_bytes = self + .try_to_vec() + .expect("Transation should be serializable"); + HEXUPPER.encode(&tx_bytes) } /// Get the transaction header diff --git a/core/src/types/account.rs b/core/src/types/account.rs index 95b8b6e2d3..d66876ba37 100644 --- a/core/src/types/account.rs +++ b/core/src/types/account.rs @@ -40,7 +40,13 @@ impl Account { } #[derive( - Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, + Debug, + Clone, + BorshSerialize, + BorshDeserialize, + Serialize, + Deserialize, + Default, )] /// Holds the public key map data as a bimap for efficient quering pub struct AccountPublicKeysMap { @@ -83,12 +89,4 @@ impl AccountPublicKeysMap { ) -> Option { self.pk_to_idx.get(public_key).cloned() } - - /// Return an empty AccountPublicKeysMap - pub fn empty() -> Self { - AccountPublicKeysMap { - pk_to_idx: HashMap::new(), - idx_to_pk: HashMap::new(), - } - } } diff --git a/core/src/types/transaction/wrapper.rs b/core/src/types/transaction/wrapper.rs index 403641a0b6..49a4f6856d 100644 --- a/core/src/types/transaction/wrapper.rs +++ b/core/src/types/transaction/wrapper.rs @@ -13,6 +13,7 @@ pub mod wrapper_tx { use sha2::{Digest, Sha256}; use thiserror::Error; + use crate::ledger::testnet_pow; use crate::types::address::Address; use crate::types::key::*; use crate::types::storage::Epoch; @@ -240,7 +241,7 @@ pub mod wrapper_tx { epoch: Epoch, gas_limit: GasLimit, #[cfg(not(feature = "mainnet"))] pow_solution: Option< - crate::ledger::testnet_pow::Solution, + testnet_pow::Solution, >, ) -> WrapperTx { Self { diff --git a/shared/src/ledger/args.rs b/shared/src/ledger/args.rs index 913cc12bb3..815dea3792 100644 --- a/shared/src/ledger/args.rs +++ b/shared/src/ledger/args.rs @@ -651,7 +651,7 @@ pub struct EthereumBridgePool { /// The account of fee payer. pub gas_payer: C::Address, /// Path to the tx WASM code file - pub code_path: C::Data, + pub code_path: PathBuf, } /// Bridge pool proof arguments. diff --git a/shared/src/ledger/eth_bridge/bridge_pool.rs b/shared/src/ledger/eth_bridge/bridge_pool.rs index fbee9fdb11..f25de56fe5 100644 --- a/shared/src/ledger/eth_bridge/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/bridge_pool.rs @@ -19,11 +19,8 @@ use crate::eth_bridge::ethers::abi::AbiDecode; use crate::eth_bridge::structs::RelayProof; use crate::ledger::args; use crate::ledger::queries::{Client, RPC}; -use crate::ledger::rpc::validate_amount; -use crate::ledger::signing::TxSigningKey; +use crate::ledger::rpc::{query_wasm_code_hash, validate_amount}; use crate::ledger::tx::{prepare_tx, Error}; -use crate::ledger::wallet::{Wallet, WalletUtils}; -use crate::proto::{Code, Data, Tx}; use crate::types::address::Address; use crate::types::control_flow::time::{Duration, Instant}; use crate::types::control_flow::{ @@ -35,34 +32,31 @@ use crate::types::eth_bridge_pool::{ }; use crate::types::keccak::KeccakHash; use crate::types::token::{Amount, DenominatedAmount}; -use crate::types::transaction::TxType; +use crate::types::tx::TxBuilder; use crate::types::voting_power::FractionalVotingPower; /// Craft a transaction that adds a transfer to the Ethereum bridge pool. -pub async fn build_bridge_pool_tx< - C: crate::ledger::queries::Client + Sync, - U: WalletUtils, ->( +pub async fn build_bridge_pool_tx( client: &C, - wallet: &mut Wallet, - args: args::EthereumBridgePool, -) -> Result<(Tx, Option
, Vec), Error> { - let args::EthereumBridgePool { - ref tx, + args::EthereumBridgePool { + tx, asset, recipient, sender, amount, gas_amount, gas_payer, - code_path: wasm_code, - } = args; - + code_path, + }: args::EthereumBridgePool, + fee_payer: common::PublicKey, +) -> Result { let sub_prefix = Some(wrapped_erc20s::sub_prefix(&asset)); + let DenominatedAmount { amount, .. } = validate_amount(client, amount, &BRIDGE_ADDRESS, &sub_prefix, tx.force) .await .expect("Failed to validate amount"); + let transfer = PendingTransfer { transfer: TransferToEthereum { asset, @@ -76,24 +70,24 @@ pub async fn build_bridge_pool_tx< }, }; - let mut transfer_tx = Tx::new(TxType::Raw); - transfer_tx.header.chain_id = tx.chain_id.clone().unwrap(); - transfer_tx.header.expiration = tx.expiration; - transfer_tx.set_data(Data::new( - transfer - .try_to_vec() - .expect("Serializing tx should not fail"), - )); + let tx_code_hash = + query_wasm_code_hash(client, code_path.to_str().unwrap()) + .await + .unwrap(); + + let chain_id = tx.chain_id.clone().unwrap(); + let tx_builder = TxBuilder::new(chain_id, tx.expiration); + // TODO: change the wasm code to a hash - transfer_tx.set_code(Code::new(wasm_code)); + let tx_builder = tx_builder + .add_code_from_hash(tx_code_hash) + .add_data(transfer); - prepare_tx::( + prepare_tx::( client, - wallet, - tx, - transfer_tx, - Some(sender), - TxSigningKey::None, + &tx, + tx_builder, + fee_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) diff --git a/shared/src/ledger/ibc/vp/mod.rs b/shared/src/ledger/ibc/vp/mod.rs index 5986a01771..730dc40f33 100644 --- a/shared/src/ledger/ibc/vp/mod.rs +++ b/shared/src/ledger/ibc/vp/mod.rs @@ -371,6 +371,7 @@ mod tests { use crate::types::time::DurationSecs; use crate::types::token::{balance_key, Amount}; use crate::types::transaction::TxType; + use crate::types::tx::TxBuilder; use crate::vm::wasm; const ADDRESS: Address = Address::Internal(InternalAddress::Ibc); @@ -805,14 +806,13 @@ mod tests { let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = wl_storage.storage.chain_id.clone(); - tx.set_code(Code::new(tx_code)); - tx.set_data(Data::new(tx_data)); - tx.add_section(Section::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &keypair_1(), - ))); + let tx_builder = + TxBuilder::new(wl_storage.storage.chain_id.clone(), None); + let tx = tx_builder + .add_code(tx_code) + .add_serialized_data(tx_data) + .add_fee_payer(keypair_1()) + .build(); let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = @@ -943,14 +943,13 @@ mod tests { let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = wl_storage.storage.chain_id.clone(); - tx.set_code(Code::new(tx_code)); - tx.set_data(Data::new(tx_data)); - tx.add_section(Section::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &keypair_1(), - ))); + let tx_builder = + TxBuilder::new(wl_storage.storage.chain_id.clone(), None); + let tx = tx_builder + .add_code(tx_code) + .add_serialized_data(tx_data) + .add_fee_payer(keypair_1()) + .build(); let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = @@ -1147,14 +1146,13 @@ mod tests { let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = wl_storage.storage.chain_id.clone(); - tx.set_code(Code::new(tx_code)); - tx.set_data(Data::new(tx_data)); - tx.add_section(Section::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &keypair_1(), - ))); + let tx_builder = + TxBuilder::new(wl_storage.storage.chain_id.clone(), None); + let tx = tx_builder + .add_code(tx_code) + .add_serialized_data(tx_data) + .add_fee_payer(keypair_1()) + .build(); let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = @@ -1275,14 +1273,15 @@ mod tests { let tx_code = vec![]; let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = wl_storage.storage.chain_id.clone(); - tx.set_code(Code::new(tx_code)); - tx.set_data(Data::new(tx_data)); - tx.add_section(Section::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &keypair_1(), - ))); + + let tx_builder = + TxBuilder::new(wl_storage.storage.chain_id.clone(), None); + let tx = tx_builder + .add_code(tx_code) + .add_serialized_data(tx_data) + .add_fee_payer(keypair_1()) + .build(); + let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = wasm::compilation_cache::common::testing::cache(); @@ -1921,14 +1920,15 @@ mod tests { let tx_code = vec![]; let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = wl_storage.storage.chain_id.clone(); - tx.set_code(Code::new(tx_code)); - tx.set_data(Data::new(tx_data)); - tx.add_section(Section::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &keypair_1(), - ))); + + let tx_builder = + TxBuilder::new(wl_storage.storage.chain_id.clone(), None); + let tx = tx_builder + .add_code(tx_code) + .add_serialized_data(tx_data) + .add_fee_payer(keypair_1()) + .build(); + let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = wasm::compilation_cache::common::testing::cache(); @@ -2058,14 +2058,15 @@ mod tests { let tx_code = vec![]; let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = wl_storage.storage.chain_id.clone(); - tx.set_code(Code::new(tx_code)); - tx.set_data(Data::new(tx_data)); - tx.add_section(Section::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &keypair_1(), - ))); + + let tx_builder = + TxBuilder::new(wl_storage.storage.chain_id.clone(), None); + let tx = tx_builder + .add_code(tx_code) + .add_serialized_data(tx_data) + .add_fee_payer(keypair_1()) + .build(); + let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = wasm::compilation_cache::common::testing::cache(); @@ -2233,14 +2234,15 @@ mod tests { let tx_code = vec![]; let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = wl_storage.storage.chain_id.clone(); - tx.set_code(Code::new(tx_code)); - tx.set_data(Data::new(tx_data)); - tx.add_section(Section::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &keypair_1(), - ))); + + let tx_builder = + TxBuilder::new(wl_storage.storage.chain_id.clone(), None); + let tx = tx_builder + .add_code(tx_code) + .add_serialized_data(tx_data) + .add_fee_payer(keypair_1()) + .build(); + let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = wasm::compilation_cache::common::testing::cache(); @@ -2377,14 +2379,15 @@ mod tests { let tx_code = vec![]; let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = wl_storage.storage.chain_id.clone(); - tx.set_code(Code::new(tx_code)); - tx.set_data(Data::new(tx_data)); - tx.add_section(Section::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &keypair_1(), - ))); + + let tx_builder = + TxBuilder::new(wl_storage.storage.chain_id.clone(), None); + let tx = tx_builder + .add_code(tx_code) + .add_serialized_data(tx_data) + .add_fee_payer(keypair_1()) + .build(); + let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = wasm::compilation_cache::common::testing::cache(); @@ -2526,14 +2529,15 @@ mod tests { let tx_code = vec![]; let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = wl_storage.storage.chain_id.clone(); - tx.set_code(Code::new(tx_code)); - tx.set_data(Data::new(tx_data)); - tx.add_section(Section::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &keypair_1(), - ))); + + let tx_builder = + TxBuilder::new(wl_storage.storage.chain_id.clone(), None); + let tx = tx_builder + .add_code(tx_code) + .add_serialized_data(tx_data) + .add_fee_payer(keypair_1()) + .build(); + let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = wasm::compilation_cache::common::testing::cache(); @@ -2675,14 +2679,15 @@ mod tests { let tx_code = vec![]; let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = wl_storage.storage.chain_id.clone(); - tx.set_code(Code::new(tx_code)); - tx.set_data(Data::new(tx_data)); - tx.add_section(Section::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &keypair_1(), - ))); + + let tx_builder = + TxBuilder::new(wl_storage.storage.chain_id.clone(), None); + let tx = tx_builder + .add_code(tx_code) + .add_serialized_data(tx_data) + .add_fee_payer(keypair_1()) + .build(); + let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = wasm::compilation_cache::common::testing::cache(); diff --git a/shared/src/ledger/native_vp/ethereum_bridge/bridge_pool_vp.rs b/shared/src/ledger/native_vp/ethereum_bridge/bridge_pool_vp.rs index 283cf52c58..bc4b5be451 100644 --- a/shared/src/ledger/native_vp/ethereum_bridge/bridge_pool_vp.rs +++ b/shared/src/ledger/native_vp/ethereum_bridge/bridge_pool_vp.rs @@ -382,13 +382,13 @@ mod test_bridge_pool_vp { use crate::ledger::storage::write_log::WriteLog; use crate::ledger::storage::{Storage, WlStorage}; use crate::ledger::storage_api::StorageWrite; - use crate::proto::Data; use crate::types::address::{nam, wnam}; use crate::types::chain::ChainId; use crate::types::eth_bridge_pool::{GasFee, TransferToEthereum}; use crate::types::hash::Hash; use crate::types::storage::TxIndex; use crate::types::transaction::TxType; + use crate::types::tx::TxBuilder; use crate::vm::wasm::VpCache; use crate::vm::WasmCacheRwAccess; @@ -649,8 +649,9 @@ mod test_bridge_pool_vp { ), }; - let mut tx = Tx::new(TxType::Raw); - tx.set_data(Data::new(transfer.try_to_vec().expect("Test failed"))); + let tx_builder = + TxBuilder::new(wl_storage.storage.chain_id.clone(), None); + let tx = tx_builder.add_data(transfer).build(); let res = vp.validate_tx(&tx, &keys_changed, &verifiers); match expect { @@ -987,8 +988,9 @@ mod test_bridge_pool_vp { ), }; - let mut tx = Tx::new(TxType::Raw); - tx.set_data(Data::new(transfer.try_to_vec().expect("Test failed"))); + let tx_builder = + TxBuilder::new(wl_storage.storage.chain_id.clone(), None); + let tx = tx_builder.add_data(transfer).build(); let res = vp.validate_tx(&tx, &keys_changed, &verifiers); assert!(!res.expect("Test failed")); @@ -1047,8 +1049,9 @@ mod test_bridge_pool_vp { ), }; - let mut tx = Tx::new(TxType::Raw); - tx.set_data(Data::new(transfer.try_to_vec().expect("Test failed"))); + let tx_builder = + TxBuilder::new(wl_storage.storage.chain_id.clone(), None); + let tx = tx_builder.add_data(transfer).build(); let res = vp .validate_tx(&tx, &keys_changed, &verifiers) @@ -1133,8 +1136,9 @@ mod test_bridge_pool_vp { ), }; - let mut tx = Tx::new(TxType::Raw); - tx.set_data(Data::new(transfer.try_to_vec().expect("Test failed"))); + let tx_builder = + TxBuilder::new(wl_storage.storage.chain_id.clone(), None); + let tx = tx_builder.add_data(transfer).build(); let res = vp .validate_tx(&tx, &keys_changed, &verifiers) @@ -1220,8 +1224,9 @@ mod test_bridge_pool_vp { ), }; - let mut tx = Tx::new(TxType::Raw); - tx.set_data(Data::new(transfer.try_to_vec().expect("Test failed"))); + let tx_builder = + TxBuilder::new(wl_storage.storage.chain_id.clone(), None); + let tx = tx_builder.add_data(transfer).build(); let res = vp .validate_tx(&tx, &keys_changed, &verifiers) @@ -1334,8 +1339,9 @@ mod test_bridge_pool_vp { ), }; - let mut tx = Tx::new(TxType::Raw); - tx.set_data(Data::new(transfer.try_to_vec().expect("Test failed"))); + let tx_builder = + TxBuilder::new(wl_storage.storage.chain_id.clone(), None); + let tx = tx_builder.add_data(transfer).build(); let res = vp .validate_tx(&tx, &keys_changed, &verifiers) diff --git a/shared/src/ledger/signing.rs b/shared/src/ledger/signing.rs index b8cdf01c3a..a5af08fbc3 100644 --- a/shared/src/ledger/signing.rs +++ b/shared/src/ledger/signing.rs @@ -1,12 +1,6 @@ //! Functions to sign transactions use std::collections::HashMap; -#[cfg(feature = "std")] -use std::env; -#[cfg(feature = "std")] -use std::fs::File; use std::io::ErrorKind; -#[cfg(feature = "std")] -use std::io::Write; use borsh::{BorshDeserialize, BorshSerialize}; use data_encoding::HEXLOWER; @@ -44,7 +38,7 @@ use crate::ledger::tx::{ pub use crate::ledger::wallet::store::AddressVpType; use crate::ledger::wallet::{Wallet, WalletUtils}; use crate::ledger::{args, rpc}; -use crate::proto::{MaspBuilder, MultiSignature, Section, Signature, Tx}; +use crate::proto::{MaspBuilder, Section, Tx}; use crate::types::key::*; use crate::types::masp::{ExtendedViewingKey, PaymentAddress}; use crate::types::storage::Epoch; @@ -54,7 +48,8 @@ use crate::types::transaction::governance::{ InitProposalData, VoteProposalData, }; use crate::types::transaction::pos::InitValidator; -use crate::types::transaction::{Fee, TxType, WrapperTx}; +use crate::types::transaction::{Fee, TxType}; +use crate::types::tx::TxBuilder; #[cfg(feature = "std")] /// Env. var specifying where to store signing test vectors @@ -63,6 +58,28 @@ const ENV_VAR_LEDGER_LOG_PATH: &str = "NAMADA_LEDGER_LOG_PATH"; /// Env. var specifying where to store transaction debug outputs const ENV_VAR_TX_LOG_PATH: &str = "NAMADA_TX_LOG_PATH"; +/// A struture holding the signing data to craft a transaction +#[derive(Clone)] +pub struct SigningTxData { + /// The public keys associated to an account + pub public_keys: Vec, + /// The threshold associated to an account + pub threshold: u8, + /// The public keys to index map associated to an account + pub account_public_keys_map: AccountPublicKeysMap, + /// The public keys of the fee payer + pub fee_payer: common::PublicKey, +} + +/// Generate a signing key from an address. Default to None if address is empty. +pub fn signer_from_address(address: Option
) -> TxSigningKey { + if let Some(address) = address { + TxSigningKey::WalletAddress(address) + } else { + TxSigningKey::None + } +} + /// Find the public key for the given address and try to load the keypair /// for it from the wallet. If the keypair is encrypted but a password is not /// supplied, then it is interactively prompted. Errors if the key cannot be @@ -146,7 +163,7 @@ pub enum TxSigningKey { /// signer. Return the given signing key or public key of the given signer if /// possible. If no explicit signer given, use the `default`. If no `default` /// is given, an `Error` is returned. -pub async fn tx_signer< +pub async fn tx_signers< C: crate::ledger::queries::Client + Sync, U: WalletUtils, >( @@ -191,15 +208,14 @@ pub async fn tx_signer< /// hashes needed for monitoring the tx on chain. /// /// If it is a dry run, it is not put in a wrapper, but returned as is. -pub async fn sign_tx( +pub fn sign_tx( wallet: &mut Wallet, - tx: &mut Tx, args: &args::Tx, - public_keys_index_map: &AccountPublicKeysMap, - public_keys: &[common::PublicKey], - threshold: u8, -) -> Result<(), Error> { - let keypairs = public_keys + tx_builder: TxBuilder, + signing_data: SigningTxData, +) -> Result { + let signing_tx_keypairs = signing_data + .public_keys .iter() .filter_map(|public_key| { match find_key_by_pk(wallet, args, public_key) { @@ -209,67 +225,68 @@ pub async fn sign_tx( }) .collect::>(); - // Sign over the transacttion data - let multisignature_section = MultiSignature::new( - vec![*tx.data_sechash(), *tx.code_sechash()], - &keypairs, - public_keys_index_map, - ); + let fee_payer_keypair = + find_key_by_pk(wallet, args, &signing_data.fee_payer).expect(""); - if (multisignature_section.total_signatures() < threshold) && !args.force { - return Err(Error::MissingSigningKeys( - threshold, - multisignature_section.total_signatures(), - )); - } + let tx_builder = tx_builder.add_signing_keys( + signing_tx_keypairs, + signing_data.account_public_keys_map, + ); + let tx_builder = tx_builder.add_fee_payer(fee_payer_keypair); - // Sign over the transaction targets - tx.add_section(Section::SectionSignature(multisignature_section)); + Ok(tx_builder) +} - // Remove all the sensitive sections - tx.protocol_filter(); +/// Return the necessary data regarding an account to be able to generate a +/// multisignature section +pub async fn aux_signing_data< + C: crate::ledger::queries::Client + Sync, + U: WalletUtils, +>( + client: &C, + wallet: &mut Wallet, + args: &args::Tx, + owner: &Address, + default_signer: TxSigningKey, +) -> Result { + let public_keys = + tx_signers::(client, wallet, args, default_signer.clone()) + .await?; + + let (account_public_keys_map, threshold) = match owner { + Address::Established(_) => { + let account = rpc::get_account_info::(client, owner).await; + if let Some(account) = account { + (account.public_keys_map, account.threshold) + } else { + return Err(Error::InvalidAccount(owner.encode())); + } + } + Address::Implicit(_) => { + (AccountPublicKeysMap::from_iter(public_keys.clone()), 1u8) + } + Address::Internal(_) => { + return Err(Error::InvalidAccount(owner.encode())); + } + }; let fee_payer = match &args.fee_payer { - Some(keypair) => keypair, + Some(keypair) => keypair.ref_to(), None => { - if let Some(public_key) = keypairs.get(0) { - public_key + if let Some(public_key) = public_keys.get(0) { + public_key.clone() } else { - return Err(Error::InvalidFeePayer( - "Either --signing-keys or --fee-payer must be available." - .to_string(), - )); + return Err(Error::InvalidFeePayer); } } }; - tx.add_section(Section::Signature(Signature::new( - tx.sechashes(), + Ok(SigningTxData { + public_keys, + threshold, + account_public_keys_map, fee_payer, - ))); - - Ok(()) -} - -/// Return the necessary data regarding an account to be able to generate a -/// multisignature section -pub async fn aux_signing_data( - client: &C, - owner: Option
, - public_keys: Vec, -) -> (AccountPublicKeysMap, u8) { - if let Some(owner) = owner { - let account = rpc::get_account_info::(client, &owner).await; - let (public_keys_index_map, threshold) = if let Some(account) = account - { - (account.public_keys_map, account.threshold) - } else { - (AccountPublicKeysMap::from_iter(public_keys), 1u8) - }; - (public_keys_index_map, threshold) - } else { - (AccountPublicKeysMap::from_iter(public_keys), 0u8) - } + }) } #[cfg(not(feature = "mainnet"))] @@ -351,70 +368,26 @@ pub async fn update_pow_challenge( /// Create a wrapper tx from a normal tx. Get the hash of the /// wrapper and its payload which is needed for monitoring its /// progress on chain. -pub async fn wrap_tx< - C: crate::ledger::queries::Client + Sync, - U: WalletUtils, ->( +pub async fn wrap_tx( client: &C, - #[allow(unused_variables)] wallet: &mut Wallet, + tx_builder: TxBuilder, args: &args::Tx, epoch: Epoch, - mut tx: Tx, - keypair: &common::PublicKey, + fee_payer: common::PublicKey, #[cfg(not(feature = "mainnet"))] requires_pow: bool, -) -> Tx { +) -> TxBuilder { #[cfg(not(feature = "mainnet"))] let (pow_solution, fee) = - solve_pow_challenge(client, args, keypair, requires_pow).await; - // This object governs how the payload will be processed - tx.update_header(TxType::Wrapper(Box::new(WrapperTx::new( + solve_pow_challenge(client, args, &fee_payer, requires_pow).await; + + tx_builder.add_wrapper( fee, - keypair.clone(), + fee_payer, epoch, args.gas_limit.clone(), #[cfg(not(feature = "mainnet"))] pow_solution, - )))); - tx.header.chain_id = args.chain_id.clone().unwrap(); - tx.header.expiration = args.expiration; - - #[cfg(feature = "std")] - // Attempt to decode the construction - if let Ok(path) = env::var(ENV_VAR_LEDGER_LOG_PATH) { - let mut tx = tx.clone(); - // Contract the large data blobs in the transaction - tx.wallet_filter(); - // Convert the transaction to Ledger format - let decoding = to_ledger_vector(client, wallet, &tx) - .await - .expect("unable to decode transaction"); - let output = serde_json::to_string(&decoding) - .expect("failed to serialize decoding"); - // Record the transaction at the identified path - let mut f = File::options() - .append(true) - .create(true) - .open(path) - .expect("failed to open test vector file"); - writeln!(f, "{},", output) - .expect("unable to write test vector to file"); - } - #[cfg(feature = "std")] - // Attempt to decode the construction - if let Ok(path) = env::var(ENV_VAR_TX_LOG_PATH) { - let mut tx = tx.clone(); - // Contract the large data blobs in the transaction - tx.wallet_filter(); - // Record the transaction at the identified path - let mut f = File::options() - .append(true) - .create(true) - .open(path) - .expect("failed to open test vector file"); - writeln!(f, "{:x?},", tx).expect("unable to write test vector to file"); - } - - tx + ) } #[allow(clippy::result_large_err)] @@ -643,6 +616,55 @@ pub async fn make_ledger_masp_endpoints< } } +/// Internal method used to generate transaction test vectors +#[cfg(feature = "std")] +pub async fn generate_test_vector< + C: crate::ledger::queries::Client + Sync, + U: WalletUtils, +>( + client: &C, + wallet: &mut Wallet, + tx: &Tx, +) { + use std::env; + use std::fs::File; + use std::io::Write; + + if let Ok(path) = env::var(ENV_VAR_LEDGER_LOG_PATH) { + let mut tx = tx.clone(); + // Contract the large data blobs in the transaction + tx.wallet_filter(); + // Convert the transaction to Ledger format + let decoding = to_ledger_vector(client, wallet, &tx) + .await + .expect("unable to decode transaction"); + let output = serde_json::to_string(&decoding) + .expect("failed to serialize decoding"); + // Record the transaction at the identified path + let mut f = File::options() + .append(true) + .create(true) + .open(path) + .expect("failed to open test vector file"); + writeln!(f, "{},", output) + .expect("unable to write test vector to file"); + } + + // Attempt to decode the construction + if let Ok(path) = env::var(ENV_VAR_TX_LOG_PATH) { + let mut tx = tx.clone(); + // Contract the large data blobs in the transaction + tx.wallet_filter(); + // Record the transaction at the identified path + let mut f = File::options() + .append(true) + .create(true) + .open(path) + .expect("failed to open test vector file"); + writeln!(f, "{:x?},", tx).expect("unable to write test vector to file"); + } +} + /// Converts the given transaction to the form that is displayed on the Ledger /// device pub async fn to_ledger_vector< diff --git a/shared/src/ledger/tx.rs b/shared/src/ledger/tx.rs index f2aba5974e..3f00409c78 100644 --- a/shared/src/ledger/tx.rs +++ b/shared/src/ledger/tx.rs @@ -1,6 +1,7 @@ //! SDK functions to construct different types of transactions use std::borrow::Cow; use std::collections::{BTreeMap, HashMap, HashSet}; +use std::fs::File; use std::str::FromStr; use std::time::Duration; @@ -25,6 +26,7 @@ use prost::EncodeError; use thiserror::Error; use super::rpc::query_wasm_code_hash; +use super::signing::wrap_tx; use crate::ibc::applications::transfer::msgs::transfer::MsgTransfer; use crate::ibc::core::ics04_channel::timeout::TimeoutHeight; use crate::ibc::signer::Signer; @@ -36,9 +38,9 @@ use crate::ledger::args::{self, InputAmount}; use crate::ledger::governance::storage as gov_storage; use crate::ledger::masp::{ShieldedContext, ShieldedUtils}; use crate::ledger::rpc::{self, validate_amount, TxBroadcastData, TxResponse}; -use crate::ledger::signing::{tx_signer, wrap_tx, TxSigningKey}; +use crate::ledger::signing::TxSigningKey; use crate::ledger::wallet::{Wallet, WalletUtils}; -use crate::proto::{Code, Data, MaspBuilder, Section, Tx}; +use crate::proto::{MaspBuilder, Tx}; use crate::tendermint_rpc::endpoint::broadcast::tx_sync::Response; use crate::tendermint_rpc::error::Error as RpcError; use crate::types::control_flow::{time, ProceedOrElse}; @@ -48,6 +50,7 @@ use crate::types::storage::{Epoch, RESERVED_ADDRESS_PREFIX}; use crate::types::time::DateTimeUtc; use crate::types::transaction::account::{InitAccount, UpdateAccount}; use crate::types::transaction::{pos, TxType}; +use crate::types::tx::TxBuilder; use crate::types::{storage, token}; use crate::vm; use crate::vm::WasmValidationError; @@ -207,15 +210,18 @@ pub enum Error { /// Epoch not in storage #[error("Proposal end epoch is not in the storage.")] EpochNotInStorage, - /// Couldn't understand who the fee pair is - #[error("{0}")] - InvalidFeePayer(String), + /// Couldn't understand who the fee payer is + #[error("Either --signing-keys or --fee-payer must be available.")] + InvalidFeePayer, /// Account threshold is not set #[error("Account threshold must be set.")] MissingAccountThreshold, /// Not enough signature #[error("Account threshold is {0} but the valid signatures are {1}.")] MissingSigningKeys(u8, u8), + /// Invalid owner account + #[error("The source account {0} is not valid or doesn't exist.")] + InvalidAccount(String), /// Other Errors that may show up when using the interface #[error("{0}")] Other(String), @@ -243,57 +249,47 @@ impl ProcessTxResponse { } } +/// Build and dump a transaction either to file or to screen +pub fn dump_tx(args: &args::Tx, tx_builder: TxBuilder) { + let tx = tx_builder.build(); + let tx_id = tx.header_hash(); + let serialized_tx = tx.serialize(); + match args.output_folder.to_owned() { + Some(path) => { + let tx_filename = format!("{}.tx", tx_id); + let out = File::create(path.join(tx_filename)).unwrap(); + serde_json::to_writer_pretty(out, &serialized_tx) + .expect("Should be able to write to file.") + } + None => println!("{}", serialized_tx), + } +} + /// Prepare a transaction for signing and submission by adding a wrapper header /// to it. -pub async fn prepare_tx< - C: crate::ledger::queries::Client + Sync, - U: WalletUtils, ->( +pub async fn prepare_tx( client: &C, - wallet: &mut Wallet, args: &args::Tx, - tx: Tx, - owner: Option
, - default_signer: TxSigningKey, + tx_builder: TxBuilder, + fee_payer: common::PublicKey, #[cfg(not(feature = "mainnet"))] requires_pow: bool, -) -> Result<(Tx, Option
, Vec), Error> { - let signer_public_keys = - tx_signer::(client, wallet, args, default_signer.clone()).await?; - - let fee_payer = match &args.fee_payer { - Some(keypair) => keypair.ref_to(), - None => { - if let Some(public_key) = signer_public_keys.get(0) { - public_key.clone() - } else { - return Err(Error::InvalidFeePayer( - "Either --signing-keys or --fee-payer must be available." - .to_string(), - )); - } - } - }; - - if args.dry_run { - Ok((tx, owner, signer_public_keys)) +) -> Result { + let tx_builder = if args.dry_run { + tx_builder } else { let epoch = rpc::query_epoch(client).await; - Ok(( - wrap_tx( - client, - wallet, - args, - epoch, - tx.clone(), - &fee_payer, - #[cfg(not(feature = "mainnet"))] - requires_pow, - ) - .await, - owner, - signer_public_keys, - )) - } + wrap_tx( + client, + tx_builder, + args, + epoch, + fee_payer, + #[cfg(not(feature = "mainnet"))] + requires_pow, + ) + .await + }; + Ok(tx_builder) } /// Submit transaction and wait for result. Returns a list of addresses @@ -305,10 +301,8 @@ pub async fn process_tx< client: &C, wallet: &mut Wallet, args: &args::Tx, - mut tx: Tx, + tx_builder: TxBuilder, ) -> Result { - // Remove all the sensitive sections - tx.protocol_filter(); // NOTE: use this to print the request JSON body: // let request = @@ -319,6 +313,14 @@ pub async fn process_tx< // let request_body = request.into_json(); // println!("HTTP request body: {}", request_body); + let tx = tx_builder.build(); + + #[cfg(feature = "std")] + { + use super::signing; + signing::generate_test_vector(client, wallet, &tx).await; + } + if args.dry_run { expect_dry_broadcast(TxBroadcastData::DryRun(tx), client).await } else { @@ -359,72 +361,38 @@ pub async fn process_tx< } } -/// Submit transaction to reveal public key -pub async fn build_reveal_pk< - C: crate::ledger::queries::Client + Sync, - U: WalletUtils, ->( +/// Check if a reveal public key transaction is needed +pub async fn is_reveal_pk_needed( client: &C, - wallet: &mut Wallet, - args: args::RevealPk, -) -> Result, Vec)>, Error> { - let args::RevealPk { - tx: args, - public_key, - } = args; - let public_key = public_key; - if !is_reveal_pk_needed::(client, &public_key, &args).await? { - let addr: Address = (&public_key).into(); - println!("PK for {addr} is already revealed, nothing to do."); - Ok(None) - } else { - // If not, submit it - Ok(Some( - build_reveal_pk_aux::(client, wallet, &public_key, &args) - .await?, - )) - } -} - -/// Submit transaction to rveeal public key if needed -pub async fn is_reveal_pk_needed< - C: crate::ledger::queries::Client + Sync, - U: WalletUtils, ->( - client: &C, - public_key: &common::PublicKey, - args: &args::Tx, + address: &Address, + force: bool, ) -> Result where C: crate::ledger::queries::Client + Sync, - U: WalletUtils, { - let addr: Address = public_key.into(); // Check if PK revealed - Ok(args.force || !has_revealed_pk(client, &addr).await) + Ok(force || !has_revealed_pk(client, address).await) } /// Check if the public key for the given address has been revealed pub async fn has_revealed_pk( client: &C, - addr: &Address, + address: &Address, ) -> bool { - rpc::is_public_key_revealed(client, addr).await + rpc::is_public_key_revealed(client, address).await } /// Submit transaction to reveal the given public key -pub async fn build_reveal_pk_aux< - C: crate::ledger::queries::Client + Sync, - U: WalletUtils, ->( +pub async fn build_reveal_pk( client: &C, - wallet: &mut Wallet, - public_key: &common::PublicKey, args: &args::Tx, -) -> Result<(Tx, Option
, Vec), Error> { - let addr: Address = public_key.into(); - println!("Submitting a tx to reveal the public key for address {addr}..."); - let tx_data = public_key.try_to_vec().map_err(Error::EncodeKeyFailure)?; + address: &Address, + public_key: &common::PublicKey, + fee_payer: &common::PublicKey, +) -> Result { + println!( + "Submitting a tx to reveal the public key for address {address}..." + ); let tx_code_hash = query_wasm_code_hash( client, @@ -433,21 +401,18 @@ pub async fn build_reveal_pk_aux< .await .unwrap(); - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = args.chain_id.clone().expect("value should be there"); - tx.header.expiration = args.expiration; - tx.set_data(Data::new(tx_data)); - tx.set_code(Code::from_hash(tx_code_hash)); + let chain_id = args.chain_id.clone().unwrap(); + let tx_builder = TxBuilder::new(chain_id, args.expiration); - let owner: Address = public_key.into(); + let tx_builder = tx_builder + .add_code_from_hash(tx_code_hash) + .add_data(public_key); - prepare_tx::( + prepare_tx::( client, - wallet, args, - tx, - Some(owner), - TxSigningKey::WalletAddress(addr), + tx_builder, + fee_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) @@ -649,16 +614,20 @@ pub async fn save_initialized_accounts( /// Submit validator comission rate change pub async fn build_validator_commission_change< C: crate::ledger::queries::Client + Sync, - U: WalletUtils, >( client: &C, - wallet: &mut Wallet, - args: args::CommissionRateChange, -) -> Result<(Tx, Option
, Vec), Error> { + args::CommissionRateChange { + tx, + validator, + rate, + tx_code_path, + }: args::CommissionRateChange, + fee_payer: &common::PublicKey, +) -> Result { let epoch = rpc::query_epoch(client).await; let tx_code_hash = - query_wasm_code_hash(client, args.tx_code_path.to_str().unwrap()) + query_wasm_code_hash(client, tx_code_path.to_str().unwrap()) .await .unwrap(); @@ -668,11 +637,11 @@ pub async fn build_validator_commission_change< .await .expect("Parameter should be defined."); - let validator = args.validator.clone(); + let validator = validator.clone(); if rpc::is_validator(client, &validator).await { - if args.rate < Dec::zero() || args.rate > Dec::one() { - eprintln!("Invalid new commission rate, received {}", args.rate); - return Err(Error::InvalidCommissionRate(args.rate)); + if rate < Dec::zero() || rate > Dec::one() { + eprintln!("Invalid new commission rate, received {}", rate); + return Err(Error::InvalidCommissionRate(rate)); } let pipeline_epoch_minus_one = epoch + params.pipeline_len - 1; @@ -688,7 +657,7 @@ pub async fn build_validator_commission_change< commission_rate, max_commission_change_per_epoch, }) => { - if args.rate.abs_diff(&commission_rate) + if rate.abs_diff(&commission_rate) > max_commission_change_per_epoch { eprintln!( @@ -696,45 +665,40 @@ pub async fn build_validator_commission_change< the predecessor epoch in which the rate will take \ effect." ); - if !args.tx.force { - return Err(Error::InvalidCommissionRate(args.rate)); + if !tx.force { + return Err(Error::InvalidCommissionRate(rate)); } } } None => { eprintln!("Error retrieving from storage"); - if !args.tx.force { + if !tx.force { return Err(Error::Retrieval); } } } } else { eprintln!("The given address {validator} is not a validator."); - if !args.tx.force { + if !tx.force { return Err(Error::InvalidValidatorAddress(validator)); } } let data = pos::CommissionChange { - validator: args.validator.clone(), - new_rate: args.rate, + validator: validator.clone(), + new_rate: rate, }; - let data = data.try_to_vec().map_err(Error::EncodeTxFailure)?; - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = args.tx.chain_id.clone().unwrap(); - tx.header.expiration = args.tx.expiration; - tx.set_data(Data::new(data)); - tx.set_code(Code::from_hash(tx_code_hash)); + let chain_id = tx.chain_id.clone().unwrap(); + let tx_builder = TxBuilder::new(chain_id, tx.expiration); + + let tx_builder = tx_builder.add_code_from_hash(tx_code_hash).add_data(data); - let default_signer = args.validator.clone(); - prepare_tx::( + prepare_tx::( client, - wallet, - &args.tx, - tx, - Some(default_signer.clone()), - TxSigningKey::WalletAddress(default_signer), + &tx, + tx_builder, + fee_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) @@ -744,115 +708,69 @@ pub async fn build_validator_commission_change< /// Submit transaction to unjail a jailed validator pub async fn build_unjail_validator< C: crate::ledger::queries::Client + Sync, - U: WalletUtils, >( client: &C, - wallet: &mut Wallet, - args: args::TxUnjailValidator, -) -> Result<(Tx, Option
, Vec), Error> { - if !rpc::is_validator(client, &args.validator).await { - eprintln!("The given address {} is not a validator.", &args.validator); - if !args.tx.force { - return Err(Error::InvalidValidatorAddress(args.validator.clone())); - } - } - - let tx_code_path = String::from_utf8(args.tx_code_path).unwrap(); - let tx_code_hash = - query_wasm_code_hash(client, tx_code_path).await.unwrap(); - - let data = args - .validator - .clone() - .try_to_vec() - .map_err(Error::EncodeTxFailure)?; - - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = args.tx.chain_id.clone().unwrap(); - tx.header.expiration = args.tx.expiration; - tx.set_data(Data::new(data)); - tx.set_code(Code::from_hash(tx_code_hash)); - - let default_signer = args.validator; - prepare_tx( - client, - wallet, - &args.tx, + args::TxUnjailValidator { tx, - Some(default_signer.clone()), - TxSigningKey::WalletAddress(default_signer), - #[cfg(not(feature = "mainnet"))] - false, - ) - .await -} - -/// Submit transaction to unjail a jailed validator -pub async fn submit_unjail_validator< - C: crate::ledger::queries::Client + Sync, - U: WalletUtils, ->( - client: &C, - wallet: &mut Wallet, - args: args::TxUnjailValidator, -) -> Result<(), Error> { - if !rpc::is_validator(client, &args.validator).await { - eprintln!("The given address {} is not a validator.", &args.validator); - if !args.tx.force { - return Err(Error::InvalidValidatorAddress(args.validator.clone())); + validator, + tx_code_path, + }: args::TxUnjailValidator, + fee_payer: &common::PublicKey, +) -> Result { + if !rpc::is_validator(client, &validator).await { + eprintln!("The given address {} is not a validator.", &validator); + if !tx.force { + return Err(Error::InvalidValidatorAddress(validator.clone())); } } - let tx_code_path = String::from_utf8(args.tx_code_path).unwrap(); + let tx_code_path = String::from_utf8(tx_code_path).unwrap(); let tx_code_hash = query_wasm_code_hash(client, tx_code_path).await.unwrap(); - let data = args - .validator + let _data = validator .clone() .try_to_vec() .map_err(Error::EncodeTxFailure)?; - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = args.tx.chain_id.clone().unwrap(); - tx.header.expiration = args.tx.expiration; - tx.set_data(Data::new(data)); - tx.set_code(Code::from_hash(tx_code_hash)); + let chain_id = tx.chain_id.clone().unwrap(); + let tx_builder = TxBuilder::new(chain_id, tx.expiration); + + let tx_builder = tx_builder + .add_code_from_hash(tx_code_hash) + .add_data(validator.clone()); - let default_signer = args.validator; prepare_tx( client, - wallet, - &args.tx, - tx, - Some(default_signer.clone()), - TxSigningKey::WalletAddress(default_signer), + &tx, + tx_builder, + fee_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) - .await?; - Ok(()) + .await } /// Submit transaction to withdraw an unbond -pub async fn build_withdraw< - C: crate::ledger::queries::Client + Sync, - U: WalletUtils, ->( +pub async fn build_withdraw( client: &C, - wallet: &mut Wallet, - args: args::Withdraw, -) -> Result<(Tx, Option
, Vec), Error> { + args::Withdraw { + tx, + validator, + source, + tx_code_path, + }: args::Withdraw, + fee_payer: &common::PublicKey, +) -> Result { let epoch = rpc::query_epoch(client).await; let validator = - known_validator_or_err(args.validator.clone(), args.tx.force, client) - .await?; + known_validator_or_err(validator.clone(), tx.force, client).await?; - let source = args.source.clone(); + let source = source.clone(); let tx_code_hash = - query_wasm_code_hash(client, args.tx_code_path.to_str().unwrap()) + query_wasm_code_hash(client, tx_code_path.to_str().unwrap()) .await .unwrap(); @@ -865,6 +783,7 @@ pub async fn build_withdraw< Some(epoch), ) .await; + if tokens.is_zero() { eprintln!( "There are no unbonded bonds ready to withdraw in the current \ @@ -872,7 +791,7 @@ pub async fn build_withdraw< epoch ); rpc::query_and_print_unbonds(client, &bond_source, &validator).await; - if !args.tx.force { + if !tx.force { return Err(Error::NoUnbondReady(epoch)); } } else { @@ -884,22 +803,17 @@ pub async fn build_withdraw< } let data = pos::Withdraw { validator, source }; - let data = data.try_to_vec().map_err(Error::EncodeTxFailure)?; - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = args.tx.chain_id.clone().unwrap(); - tx.header.expiration = args.tx.expiration; - tx.set_data(Data::new(data)); - tx.set_code(Code::from_hash(tx_code_hash)); + let chain_id = tx.chain_id.clone().unwrap(); + let tx_builder = TxBuilder::new(chain_id, tx.expiration); - let default_signer = args.source.unwrap_or(args.validator); - prepare_tx::( + let tx_builder = tx_builder.add_code_from_hash(tx_code_hash).add_data(data); + + prepare_tx::( client, - wallet, - &args.tx, - tx, - Some(default_signer.clone()), - TxSigningKey::WalletAddress(default_signer), + &tx, + tx_builder, + fee_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) @@ -912,50 +826,48 @@ pub async fn build_unbond< U: WalletUtils, >( client: &C, - wallet: &mut Wallet, - args: args::Unbond, -) -> Result< - ( - Tx, - Option
, - Vec, - Option<(Epoch, token::Amount)>, - ), - Error, -> { - let source = args.source.clone(); + _wallet: &mut Wallet, + args::Unbond { + tx, + validator, + amount, + source, + tx_code_path, + }: args::Unbond, + fee_payer: &common::PublicKey, +) -> Result<(TxBuilder, Option<(Epoch, token::Amount)>), Error> { + let source = source.clone(); // Check the source's current bond amount - let bond_source = source.clone().unwrap_or_else(|| args.validator.clone()); + let bond_source = source.clone().unwrap_or_else(|| validator.clone()); let tx_code_hash = - query_wasm_code_hash(client, args.tx_code_path.to_str().unwrap()) + query_wasm_code_hash(client, tx_code_path.to_str().unwrap()) .await .unwrap(); - if !args.tx.force { - known_validator_or_err(args.validator.clone(), args.tx.force, client) - .await?; + if !tx.force { + known_validator_or_err(validator.clone(), tx.force, client).await?; let bond_amount = - rpc::query_bond(client, &bond_source, &args.validator, None).await; + rpc::query_bond(client, &bond_source, &validator, None).await; println!( "Bond amount available for unbonding: {} NAM", bond_amount.to_string_native() ); - if args.amount > bond_amount { + if amount > bond_amount { eprintln!( "The total bonds of the source {} is lower than the amount to \ be unbonded. Amount to unbond is {} and the total bonds is \ {}.", bond_source, - args.amount.to_string_native(), + amount.to_string_native(), bond_amount.to_string_native() ); - if !args.tx.force { + if !tx.force { return Err(Error::LowerBondThanUnbond( bond_source, - args.amount.to_string_native(), + amount.to_string_native(), bond_amount.to_string_native(), )); } @@ -964,8 +876,7 @@ pub async fn build_unbond< // Query the unbonds before submitting the tx let unbonds = - rpc::query_unbond_with_slashing(client, &bond_source, &args.validator) - .await; + rpc::query_unbond_with_slashing(client, &bond_source, &validator).await; let mut withdrawable = BTreeMap::::new(); for ((_start_epoch, withdraw_epoch), amount) in unbonds.into_iter() { let to_withdraw = withdrawable.entry(withdraw_epoch).or_default(); @@ -974,32 +885,28 @@ pub async fn build_unbond< let latest_withdrawal_pre = withdrawable.into_iter().last(); let data = pos::Unbond { - validator: args.validator.clone(), - amount: args.amount, - source, + validator: validator.clone(), + amount, + source: source.clone(), }; - let data = data.try_to_vec().map_err(Error::EncodeTxFailure)?; - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = args.tx.chain_id.clone().unwrap(); - tx.header.expiration = args.tx.expiration; - tx.set_data(Data::new(data)); - tx.set_code(Code::from_hash(tx_code_hash)); + let chain_id = tx.chain_id.clone().unwrap(); + let tx_builder = TxBuilder::new(chain_id, tx.expiration); + + let tx_builder = tx_builder.add_code_from_hash(tx_code_hash).add_data(data); - let default_signer = args.source.unwrap_or_else(|| args.validator.clone()); - let (tx, signer_addr, public_keys) = prepare_tx::( + let _default_signer = source.unwrap_or_else(|| validator.clone()); + let tx_builder = prepare_tx::( client, - wallet, - &args.tx, - tx, - Some(default_signer.clone()), - TxSigningKey::WalletAddress(default_signer.clone()), + &tx, + tx_builder, + fee_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) .await?; - Ok((tx, signer_addr, public_keys, latest_withdrawal_pre)) + Ok((tx_builder, latest_withdrawal_pre)) } /// Query the unbonds post-tx @@ -1065,22 +972,25 @@ pub async fn query_unbonds( } /// Submit a transaction to bond -pub async fn build_bond< - C: crate::ledger::queries::Client + Sync, - U: WalletUtils, ->( +pub async fn build_bond( client: &C, - wallet: &mut Wallet, - args: args::Bond, -) -> Result<(Tx, Option
, Vec), Error> { + args::Bond { + tx, + validator, + amount, + source, + native_token, + tx_code_path, + }: args::Bond, + fee_payer: &common::PublicKey, +) -> Result { let validator = - known_validator_or_err(args.validator.clone(), args.tx.force, client) - .await?; + known_validator_or_err(validator.clone(), tx.force, client).await?; // Check that the source address exists on chain - let source = args.source.clone(); - let source = match args.source.clone() { - Some(source) => source_exists_or_err(source, args.tx.force, client) + let source = source.clone(); + let source = match source.clone() { + Some(source) => source_exists_or_err(source, tx.force, client) .await .map(Some), None => Ok(source), @@ -1088,45 +998,40 @@ pub async fn build_bond< // Check bond's source (source for delegation or validator for self-bonds) // balance let bond_source = source.as_ref().unwrap_or(&validator); - let balance_key = token::balance_key(&args.native_token, bond_source); + let balance_key = token::balance_key(&native_token, bond_source); // TODO Should we state the same error message for the native token? check_balance_too_low_err( - &args.native_token, + &native_token, bond_source, - args.amount, + amount, balance_key, - args.tx.force, + tx.force, client, ) .await?; let tx_code_hash = - query_wasm_code_hash(client, args.tx_code_path.to_str().unwrap()) + query_wasm_code_hash(client, tx_code_path.to_str().unwrap()) .await .unwrap(); - let bond = pos::Bond { + let data = pos::Bond { validator, - amount: args.amount, + amount, source, }; - let data = bond.try_to_vec().map_err(Error::EncodeTxFailure)?; - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = args.tx.chain_id.clone().unwrap(); - tx.header.expiration = args.tx.expiration; - tx.set_data(Data::new(data)); - tx.set_code(Code::from_hash(tx_code_hash)); + let chain_id = tx.chain_id.clone().unwrap(); + let tx_builder = TxBuilder::new(chain_id, tx.expiration); - let default_signer = args.source.unwrap_or(args.validator); - prepare_tx::( + let tx_builder = tx_builder.add_code_from_hash(tx_code_hash).add_data(data); + + prepare_tx::( client, - wallet, - &args.tx, - tx, - Some(default_signer.clone()), - TxSigningKey::WalletAddress(default_signer), + &tx, + tx_builder, + fee_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) @@ -1164,24 +1069,31 @@ pub async fn is_safe_voting_window( } /// Submit an IBC transfer -pub async fn build_ibc_transfer< - C: crate::ledger::queries::Client + Sync, - U: WalletUtils, ->( +pub async fn build_ibc_transfer( client: &C, - wallet: &mut Wallet, - args: args::TxIbcTransfer, -) -> Result<(Tx, Option
, Vec), Error> { + args::TxIbcTransfer { + tx, + source, + receiver, + token, + sub_prefix, + amount, + port_id, + channel_id, + timeout_height, + timeout_sec_offset, + tx_code_path, + }: args::TxIbcTransfer, + fee_payer: &common::PublicKey, +) -> Result { // Check that the source address exists on chain - let source = - source_exists_or_err(args.source.clone(), args.tx.force, client) - .await?; + let source = source_exists_or_err(source.clone(), tx.force, client).await?; // We cannot check the receiver - let token = token_exists_or_err(args.token, args.tx.force, client).await?; + let token = token_exists_or_err(token, tx.force, client).await?; // Check source balance - let (sub_prefix, balance_key) = match args.sub_prefix { + let (sub_prefix, balance_key) = match sub_prefix { Some(sub_prefix) => { let sub_prefix = storage::Key::parse(sub_prefix).unwrap(); let prefix = token::multitoken_balance_prefix(&token, &sub_prefix); @@ -1196,15 +1108,15 @@ pub async fn build_ibc_transfer< check_balance_too_low_err( &token, &source, - args.amount, + amount, balance_key, - args.tx.force, + tx.force, client, ) .await?; let tx_code_hash = - query_wasm_code_hash(client, args.tx_code_path.to_str().unwrap()) + query_wasm_code_hash(client, tx_code_path.to_str().unwrap()) .await .unwrap(); @@ -1213,8 +1125,7 @@ pub async fn build_ibc_transfer< Some(sp) => sp.to_string().replace(RESERVED_ADDRESS_PREFIX, ""), None => token.to_string(), }; - let amount = args - .amount + let amount = amount .to_string_native() .split('.') .next() @@ -1223,7 +1134,7 @@ pub async fn build_ibc_transfer< let token = Coin { denom, amount }; // this height should be that of the destination chain, not this chain - let timeout_height = match args.timeout_height { + let timeout_height = match timeout_height { Some(h) => { TimeoutHeight::At(IbcHeight::new(0, h).expect("invalid height")) } @@ -1232,7 +1143,7 @@ pub async fn build_ibc_transfer< let now: crate::tendermint::Time = DateTimeUtc::now().try_into().unwrap(); let now: IbcTimestamp = now.into(); - let timeout_timestamp = if let Some(offset) = args.timeout_sec_offset { + let timeout_timestamp = if let Some(offset) = timeout_sec_offset { (now + Duration::new(offset, 0)).unwrap() } else if timeout_height == TimeoutHeight::Never { // we cannot set 0 to both the height and the timestamp @@ -1242,33 +1153,32 @@ pub async fn build_ibc_transfer< }; let msg = MsgTransfer { - port_id_on_a: args.port_id, - chan_id_on_a: args.channel_id, + port_id_on_a: port_id, + chan_id_on_a: channel_id, token, sender: Signer::from_str(&source.to_string()).expect("invalid signer"), - receiver: Signer::from_str(&args.receiver).expect("invalid signer"), + receiver: Signer::from_str(&receiver).expect("invalid signer"), timeout_height_on_b: timeout_height, timeout_timestamp_on_b: timeout_timestamp, }; - tracing::debug!("IBC transfer message {:?}", msg); + let any_msg = msg.to_any(); let mut data = vec![]; prost::Message::encode(&any_msg, &mut data) .map_err(Error::EncodeFailure)?; - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = args.tx.chain_id.clone().unwrap(); - tx.header.expiration = args.tx.expiration; - tx.set_data(Data::new(data)); - tx.set_code(Code::from_hash(tx_code_hash)); + let chain_id = tx.chain_id.clone().unwrap(); + + let tx_builder = TxBuilder::new(chain_id, tx.expiration); + let tx_builder = tx_builder + .add_code_from_hash(tx_code_hash) + .add_serialized_data(data); - prepare_tx::( + prepare_tx::( client, - wallet, - &args.tx, - tx, - Some(args.source.clone()), - TxSigningKey::WalletAddress(args.source), + &tx, + tx_builder, + fee_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) @@ -1351,23 +1261,13 @@ async fn used_asset_types< /// Submit an ordinary transfer pub async fn build_transfer< C: crate::ledger::queries::Client + Sync, - V: WalletUtils, U: ShieldedUtils, >( client: &C, - wallet: &mut Wallet, shielded: &mut ShieldedContext, mut args: args::TxTransfer, -) -> Result< - ( - Tx, - Option
, - Vec, - Option, - bool, - ), - Error, -> { + fee_payer: &common::PublicKey, +) -> Result<(TxBuilder, Option), Error> { let source = args.source.effective_address(); let target = args.target.effective_address(); let token = args.token.clone(); @@ -1437,7 +1337,7 @@ pub async fn build_transfer< } else { (validated_amount.amount, token, false) }; - let default_signer = + let _default_signer = TxSigningKey::WalletAddress(args.source.effective_address()); // Determine whether to pin this transaction to a storage key @@ -1475,37 +1375,38 @@ pub async fn build_transfer< Err(err) => Err(Error::MaspError(err)), }?; - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = args.tx.chain_id.clone().unwrap(); - tx.header.expiration = args.tx.expiration; + let chain_id = args.tx.chain_id.clone().unwrap(); + let tx_builder = TxBuilder::new(chain_id, args.tx.expiration); + // Add the MASP Transaction and its Builder to facilitate validation - let (masp_hash, shielded_tx_epoch) = if let Some(shielded_parts) = - shielded_parts - { - // Add a MASP Transaction section to the Tx - let masp_tx = tx.add_section(Section::MaspTx(shielded_parts.1)); - // Get the hash of the MASP Transaction section - let masp_hash = masp_tx.get_hash(); - // Get the decoded asset types used in the transaction to give - // offline wallet users more information - let asset_types = used_asset_types(shielded, client, &shielded_parts.0) - .await - .unwrap_or_default(); - // Add the MASP Transaction's Builder to the Tx - tx.add_section(Section::MaspBuilder(MaspBuilder { - asset_types, - // Store how the Info objects map to Descriptors/Outputs - metadata: shielded_parts.2, - // Store the data that was used to construct the Transaction - builder: shielded_parts.0, - // Link the Builder to the Transaction by hash code - target: masp_hash, - })); - // The MASP Transaction section hash will be used in Transfer - (Some(masp_hash), Some(shielded_parts.3)) - } else { - (None, None) - }; + let (tx_builder, masp_hash, shielded_tx_epoch) = + if let Some(shielded_parts) = shielded_parts { + // Add a MASP Transaction section to the Tx and get the tx hash + let (tx_builder, masp_tx_hash) = + tx_builder.add_masp_tx_section(shielded_parts.1); + + // Get the decoded asset types used in the transaction to give + // offline wallet users more information + let asset_types = + used_asset_types(shielded, client, &shielded_parts.0) + .await + .unwrap_or_default(); + + let tx_builder = tx_builder.add_masp_builder(MaspBuilder { + asset_types, + // Store how the Info objects map to Descriptors/Outputs + metadata: shielded_parts.2, + // Store the data that was used to construct the Transaction + builder: shielded_parts.0, + // Link the Builder to the Transaction by hash code + target: masp_tx_hash, + }); + + // The MASP Transaction section hash will be used in Transfer + (tx_builder, Some(masp_tx_hash), Some(shielded_parts.3)) + } else { + (tx_builder, None, None) + }; // Construct the corresponding transparent Transfer object let transfer = token::Transfer { source: source.clone(), @@ -1518,73 +1419,49 @@ pub async fn build_transfer< shielded: masp_hash, }; - #[cfg(not(feature = "mainnet"))] - let owner = if is_source_faucet || source == masp_addr { - None - } else { - Some(source.clone()) - }; - - #[cfg(feature = "mainnet")] - let owner = if source == masp_addr { - None - } else { - Some(source.clone()) - }; - tracing::debug!("Transfer data {:?}", transfer); - // Encode the Transfer and store it beside the MASP transaction - let data = transfer - .try_to_vec() - .expect("Encoding tx data shouldn't fail"); - tx.set_data(Data::new(data)); - // Finally store the Traansfer WASM code in the Tx - tx.set_code(Code::from_hash(tx_code_hash)); + + let tx_builder = tx_builder + .add_code_from_hash(tx_code_hash) + .add_data(transfer); // Dry-run/broadcast/submit the transaction - let (tx, signer_addr, public_keys) = prepare_tx::( + let tx_builder = prepare_tx::( client, - wallet, &args.tx, - tx, - owner, - default_signer.clone(), + tx_builder, + fee_payer.clone(), #[cfg(not(feature = "mainnet"))] is_source_faucet, ) .await?; - Ok(( - tx, - signer_addr, - public_keys, - shielded_tx_epoch, - is_source_faucet, - )) + Ok((tx_builder, shielded_tx_epoch)) } /// Submit a transaction to initialize an account -pub async fn build_init_account< - C: crate::ledger::queries::Client + Sync, - U: WalletUtils, ->( +pub async fn build_init_account( client: &C, - wallet: &mut Wallet, - args: args::TxInitAccount, -) -> Result<(Tx, Option
, Vec), Error> { - let public_keys = args.public_keys; - + args::TxInitAccount { + tx, + vp_code_path, + tx_code_path, + public_keys, + threshold, + }: args::TxInitAccount, + fee_payer: &common::PublicKey, +) -> Result { let vp_code_hash = - query_wasm_code_hash(client, args.vp_code_path.to_str().unwrap()) + query_wasm_code_hash(client, vp_code_path.to_str().unwrap()) .await .unwrap(); let tx_code_hash = - query_wasm_code_hash(client, args.tx_code_path.to_str().unwrap()) + query_wasm_code_hash(client, tx_code_path.to_str().unwrap()) .await .unwrap(); - let threshold = match args.threshold { + let threshold = match threshold { Some(threshold) => threshold, None => { if public_keys.len() == 1 { @@ -1595,28 +1472,25 @@ pub async fn build_init_account< } }; - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = args.tx.chain_id.clone().unwrap(); - tx.header.expiration = args.tx.expiration; - let extra = - tx.add_section(Section::ExtraData(Code::from_hash(vp_code_hash))); + let chain_id = tx.chain_id.clone().unwrap(); + let tx_builder = TxBuilder::new(chain_id, tx.expiration); + + let (tx_builder, extra_section_hash) = + tx_builder.add_extra_section_from_hash(vp_code_hash); - let data: InitAccount = InitAccount { + let data = InitAccount { public_keys, - vp_code_hash: extra.get_hash(), + vp_code_hash: extra_section_hash, threshold, }; - let data = data.try_to_vec().map_err(Error::EncodeTxFailure)?; - tx.set_data(Data::new(data)); - tx.set_code(Code::from_hash(tx_code_hash)); - prepare_tx::( + let tx_builder = tx_builder.add_code_from_hash(tx_code_hash).add_data(data); + + prepare_tx::( client, - wallet, - &args.tx, - tx, - None, - TxSigningKey::None, + &tx, + tx_builder, + fee_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) @@ -1624,60 +1498,28 @@ pub async fn build_init_account< } /// Submit a transaction to update a VP -pub async fn build_update_account< - C: crate::ledger::queries::Client + Sync, - U: WalletUtils, ->( +pub async fn build_update_account( client: &C, - wallet: &mut Wallet, - args: args::TxUpdateAccount, -) -> Result<(Tx, Option
, Vec), Error> { - let addr = args.addr.clone(); - - // Check that the address is established and exists on chain - match &addr { - Address::Established(_) => { - let exists = rpc::known_address::(client, &addr).await; - if !exists { - if args.tx.force { - eprintln!("The address {} doesn't exist on chain.", addr); - Ok(()) - } else { - Err(Error::LocationDoesNotExist(addr.clone())) - } - } else { - Ok(()) - } - } - Address::Implicit(_) => { - if args.tx.force { - eprintln!( - "A validity predicate of an implicit address cannot be \ - directly updated. You can use an established address for \ - this purpose." - ); - Ok(()) - } else { - Err(Error::ImplicitUpdate) - } - } - Address::Internal(_) => { - if args.tx.force { - eprintln!( - "A validity predicate of an internal address cannot be \ - directly updated." - ); - Ok(()) - } else { - Err(Error::ImplicitInternalError) - } - } - }?; - - let public_keys = args.public_keys; - let threshold = args.threshold; + args::TxUpdateAccount { + tx, + vp_code_path, + tx_code_path, + addr, + public_keys, + threshold, + }: args::TxUpdateAccount, + fee_payer: &common::PublicKey, +) -> Result { + let addr = if let Some(account) = rpc::get_account_info(client, &addr).await + { + account.address + } else if tx.force { + addr + } else { + return Err(Error::LocationDoesNotExist(addr)); + }; - let vp_code_hash = match args.vp_code_path { + let vp_code_hash = match vp_code_path { Some(code_path) => { let vp_hash = query_wasm_code_hash(client, code_path.to_str().unwrap()) @@ -1689,41 +1531,36 @@ pub async fn build_update_account< }; let tx_code_hash = - query_wasm_code_hash(client, args.tx_code_path.to_str().unwrap()) + query_wasm_code_hash(client, tx_code_path.to_str().unwrap()) .await .unwrap(); - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = args.tx.chain_id.clone().unwrap(); - tx.header.expiration = args.tx.expiration; + let chain_id = tx.chain_id.clone().unwrap(); + let tx_builder = TxBuilder::new(chain_id, tx.expiration); - let extra_hash = match vp_code_hash { + let (tx_builder, extra_section_hash) = match vp_code_hash { Some(vp_code_hash) => { - let tx_section = tx - .add_section(Section::ExtraData(Code::from_hash(vp_code_hash))); - Some(tx_section.get_hash()) + let (tx_builder, hash) = + tx_builder.add_extra_section_from_hash(vp_code_hash); + (tx_builder, Some(hash)) } - None => None, + None => (tx_builder, None), }; let data = UpdateAccount { addr, - vp_code_hash: extra_hash, + vp_code_hash: extra_section_hash, public_keys, threshold, }; - let data = data.try_to_vec().map_err(Error::EncodeTxFailure)?; - tx.set_data(Data::new(data)); - tx.set_code(Code::from_hash(tx_code_hash)); + let tx_builder = tx_builder.add_code_from_hash(tx_code_hash).add_data(data); - prepare_tx::( + prepare_tx::( client, - wallet, - &args.tx, - tx, - Some(args.addr.clone()), - TxSigningKey::WalletAddress(args.addr), + &tx, + tx_builder, + fee_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) @@ -1731,28 +1568,30 @@ pub async fn build_update_account< } /// Submit a custom transaction -pub async fn build_custom< - C: crate::ledger::queries::Client + Sync, - U: WalletUtils, ->( +pub async fn build_custom( client: &C, - wallet: &mut Wallet, - args: args::TxCustom, -) -> Result<(Tx, Option
, Vec), Error> { - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = args.tx.chain_id.clone().unwrap(); - tx.header.expiration = args.tx.expiration; - - args.data_path.map(|data| tx.set_data(Data::new(data))); - tx.set_code(Code::new(args.code_path)); + args::TxCustom { + tx, + code_path, + data_path, + owner: _, + }: &args::TxCustom, + fee_payer: &common::PublicKey, +) -> Result { + let chain_id = tx.chain_id.clone().unwrap(); + + let mut tx_builder = TxBuilder::new(chain_id, tx.expiration); + tx_builder = tx_builder.add_code(code_path.to_vec()); + + if let Some(data) = data_path { + tx_builder = tx_builder.add_data(data); + } - prepare_tx::( + prepare_tx::( client, - wallet, - &args.tx, tx, - Some(args.owner), - TxSigningKey::None, + tx_builder, + fee_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) diff --git a/shared/src/types/mod.rs b/shared/src/types/mod.rs index 4f1a795d40..64e8ce7e29 100644 --- a/shared/src/types/mod.rs +++ b/shared/src/types/mod.rs @@ -3,6 +3,7 @@ pub mod control_flow; pub mod ibc; pub mod key; +pub mod tx; pub use namada_core::types::{ address, chain, dec, eth_abi, eth_bridge_pool, ethereum_events, governance, diff --git a/shared/src/vm/wasm/run.rs b/shared/src/vm/wasm/run.rs index 9ac4852eed..861b525d8b 100644 --- a/shared/src/vm/wasm/run.rs +++ b/shared/src/vm/wasm/run.rs @@ -482,6 +482,7 @@ mod tests { use crate::proto::{Code, Data}; use crate::types::hash::Hash; use crate::types::transaction::TxType; + use crate::types::tx::TxBuilder; use crate::types::validity_predicate::EvalVp; use crate::vm::wasm; @@ -617,18 +618,21 @@ mod tests { // Allocating `2^23` (8 MiB) should be below the memory limit and // shouldn't fail let input = 2_usize.pow(23).try_to_vec().unwrap(); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(input)); + + let tx_builder = TxBuilder::new(storage.chain_id.clone(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(input) + .build(); + let eval_vp = EvalVp { vp_code_hash: limit_code_hash, input: tx, }; - let tx_data = eval_vp.try_to_vec().unwrap(); - let mut outer_tx = Tx::new(TxType::Raw); - outer_tx.header.chain_id = storage.chain_id.clone(); - outer_tx.set_code(Code::new(vec![])); - outer_tx.set_data(Data::new(tx_data)); + + let tx_builder = TxBuilder::new(storage.chain_id.clone(), None); + let outer_tx = tx_builder.add_code(vec![]).add_data(eval_vp).build(); + let (vp_cache, _) = wasm::compilation_cache::common::testing::cache(); // When the `eval`ed VP doesn't run out of memory, it should return // `true` @@ -652,18 +656,17 @@ mod tests { // Allocating `2^24` (16 MiB) should be above the memory limit and // should fail let input = 2_usize.pow(24).try_to_vec().unwrap(); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(input)); + let tx_builder = TxBuilder::new(storage.chain_id.clone(), None); + let tx = tx_builder.add_code(vec![]).add_data(input).build(); + let eval_vp = EvalVp { vp_code_hash: limit_code_hash, input: tx, }; - let tx_data = eval_vp.try_to_vec().unwrap(); - let mut outer_tx = Tx::new(TxType::Raw); - outer_tx.header.chain_id = storage.chain_id.clone(); - outer_tx.set_data(Data::new(tx_data)); - outer_tx.set_code(Code::new(vec![])); + + let tx_builder = TxBuilder::new(storage.chain_id.clone(), None); + let outer_tx = tx_builder.add_code(vec![]).add_data(eval_vp).build(); + // When the `eval`ed VP runs out of memory, its result should be // `false`, hence we should also get back `false` from the VP that // called `eval`. @@ -1022,18 +1025,21 @@ mod tests { // Borsh. storage.write(&key, value.try_to_vec().unwrap()).unwrap(); let input = 2_usize.pow(23).try_to_vec().unwrap(); - let mut tx = Tx::new(TxType::Raw); - tx.set_data(Data::new(input)); - tx.set_code(Code::new(vec![])); + + let tx_builder = TxBuilder::new(storage.chain_id.clone(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(input) + .build(); + let eval_vp = EvalVp { vp_code_hash: read_code_hash, input: tx, }; - let tx_data = eval_vp.try_to_vec().unwrap(); - let mut outer_tx = Tx::new(TxType::Raw); - outer_tx.header.chain_id = storage.chain_id.clone(); - outer_tx.set_data(Data::new(tx_data)); - outer_tx.set_code(Code::new(vec![])); + + let tx_builder = TxBuilder::new(storage.chain_id.clone(), None); + let outer_tx = tx_builder.add_code(vec![]).add_data(eval_vp).build(); + let (vp_cache, _) = wasm::compilation_cache::common::testing::cache(); let passed = vp( &code_hash, diff --git a/tests/src/native_vp/eth_bridge_pool.rs b/tests/src/native_vp/eth_bridge_pool.rs index 2829029abf..a794057058 100644 --- a/tests/src/native_vp/eth_bridge_pool.rs +++ b/tests/src/native_vp/eth_bridge_pool.rs @@ -9,7 +9,7 @@ mod test_bridge_pool_vp { ADDRESS, }; use namada::ledger::native_vp::ethereum_bridge::bridge_pool_vp::BridgePoolVp; - use namada::proto::{Code, Data, Section, Signature, Tx}; + use namada::proto::Tx; use namada::types::address::{nam, wnam}; use namada::types::chain::ChainId; use namada::types::eth_bridge_pool::{ @@ -18,7 +18,7 @@ mod test_bridge_pool_vp { use namada::types::ethereum_events::EthAddress; use namada::types::key::{common, ed25519, SecretKey}; use namada::types::token::Amount; - use namada::types::transaction::TxType; + use namada::types::tx::TxBuilder; use namada_apps::wallet::defaults::{albert_address, bertha_address}; use namada_apps::wasm_loader; @@ -124,15 +124,13 @@ mod test_bridge_pool_vp { let data = transfer.try_to_vec().expect("Test failed"); let wasm_code = wasm_loader::read_wasm_or_exit(wasm_dir(), ADD_TRANSFER_WASM); - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = ChainId::default(); - tx.set_data(Data::new(data)); - tx.set_code(Code::new(wasm_code)); - tx.add_section(Section::Signature(Signature::new( - vec![*tx.data_sechash(), *tx.code_sechash()], - keypair, - ))); - tx + + let tx_builder = TxBuilder::new(ChainId::default(), None); + tx_builder + .add_code(wasm_code) + .add_serialized_data(data) + .add_fee_payer(keypair.clone()) + .build() } #[test] diff --git a/tests/src/vm_host_env/mod.rs b/tests/src/vm_host_env/mod.rs index 3b2cec2c2e..40e549c8f7 100644 --- a/tests/src/vm_host_env/mod.rs +++ b/tests/src/vm_host_env/mod.rs @@ -27,18 +27,17 @@ mod tests { get_dummy_header as tm_dummy_header, Error as IbcError, }; use namada::ledger::tx_env::TxEnv; - use namada::proto::{Code, Data, Section, Tx}; use namada::types::hash::Hash; use namada::types::key::*; use namada::types::storage::{self, BlockHash, BlockHeight, Key, KeySeg}; use namada::types::time::DateTimeUtc; use namada::types::token::{self, Amount}; - use namada::types::transaction::TxType; + use namada::types::tx::TxBuilder; use namada::types::{address, key}; use namada_core::ledger::ibc::context::transfer_mod::testing::DummyTransferModule; use namada_core::ledger::ibc::Error as IbcActionError; - use namada_core::proto::MultiSignature; use namada_test_utils::TestWasms; + use namada_tx_prelude::chain::ChainId; use namada_tx_prelude::{BorshSerialize, StorageRead, StorageWrite}; use namada_vp_prelude::account::AccountPublicKeysMap; use namada_vp_prelude::VpEnv; @@ -458,17 +457,15 @@ mod tests { let keypairs = vec![keypair.clone()]; let pks_map = AccountPublicKeysMap::from_iter(vec![pk.clone()]); let signed_tx_data = vp_host_env::with(|env| { - let mut tx = Tx::new(TxType::Raw); - tx.header.chain_id = env.wl_storage.storage.chain_id.clone(); - tx.header.expiration = expiration; - tx.set_code(Code::new(code.clone())); - tx.set_data(Data::new(data.clone())); - - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &keypairs, - &pks_map, - ))); + let chain_id = env.wl_storage.storage.chain_id.clone(); + let tx_builder = TxBuilder::new(chain_id, expiration); + let tx = tx_builder + .add_code(code.clone()) + .add_serialized_data(data.to_vec()) + .add_fee_payer(keypair.clone()) + .add_signing_keys(keypairs.clone(), pks_map.clone()) + .build(); + env.tx = tx; env.tx.clone() }); @@ -553,16 +550,19 @@ mod tests { // evaluating without any code should fail let empty_code = Hash::zero(); let input_data = vec![]; - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(input_data)); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let keypair = key::testing::keypair_1(); + let keypairs = vec![keypair.clone()]; + let pks_map = AccountPublicKeysMap::from_iter([ + key::testing::keypair_1().ref_to(), + ]); + + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(input_data.clone()) + .add_fee_payer(keypair.clone()) + .add_signing_keys(keypairs.clone(), pks_map.clone()) + .build(); let result = vp::CTX.eval(empty_code, tx).unwrap(); assert!(!result); @@ -574,17 +574,13 @@ mod tests { let key = Key::wasm_code(&code_hash); env.wl_storage.storage.write(&key, code.clone()).unwrap(); }); - let input_data = vec![]; - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(input_data)); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code_from_hash(code_hash) + .add_serialized_data(input_data.clone()) + .add_fee_payer(keypair.clone()) + .add_signing_keys(keypairs.clone(), pks_map.clone()) + .build(); let result = vp::CTX.eval(code_hash, tx).unwrap(); assert!(result); @@ -597,17 +593,13 @@ mod tests { let key = Key::wasm_code(&code_hash); env.wl_storage.storage.write(&key, code.clone()).unwrap(); }); - let input_data = vec![]; - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(input_data)); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code_from_hash(code_hash) + .add_serialized_data(input_data) + .add_fee_payer(keypair) + .add_signing_keys(keypairs, pks_map) + .build(); let result = vp::CTX.eval(code_hash, tx).unwrap(); assert!(!result); } @@ -618,21 +610,23 @@ mod tests { tx_host_env::init(); ibc::init_storage(); + let keypair = key::testing::keypair_1(); + let keypairs = vec![keypair.clone()]; + let pks_map = AccountPublicKeysMap::from_iter([ + key::testing::keypair_1().ref_to(), + ]); // Start a transaction to create a new client let msg = ibc::msg_create_client(); let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair.clone()) + .add_signing_keys(keypairs.clone(), pks_map.clone()) + .build(); // create a client with the message tx_host_env::ibc::ibc_actions(tx::ctx()) @@ -662,16 +656,13 @@ mod tests { let msg = ibc::msg_update_client(client_id); let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair) + .add_signing_keys(keypairs, pks_map) + .build(); // update the client with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -688,6 +679,12 @@ mod tests { // The environment must be initialized first tx_host_env::init(); + let keypair = key::testing::keypair_1(); + let keypairs = vec![keypair.clone()]; + let pks_map = AccountPublicKeysMap::from_iter([ + key::testing::keypair_1().ref_to(), + ]); + // Set the initial state before starting transactions ibc::init_storage(); let (client_id, client_state, writes) = ibc::prepare_client(); @@ -704,16 +701,13 @@ mod tests { let msg = ibc::msg_connection_open_init(client_id); let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair.clone()) + .add_signing_keys(keypairs.clone(), pks_map.clone()) + .build(); // init a connection with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -742,16 +736,13 @@ mod tests { let msg = ibc::msg_connection_open_ack(conn_id, client_state); let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair) + .add_signing_keys(keypairs, pks_map) + .build(); // open the connection with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -771,6 +762,12 @@ mod tests { // Set the initial state before starting transactions ibc::init_storage(); + let keypair = key::testing::keypair_1(); + let keypairs = vec![keypair.clone()]; + let pks_map = AccountPublicKeysMap::from_iter([ + key::testing::keypair_1().ref_to(), + ]); + let (client_id, client_state, writes) = ibc::prepare_client(); writes.into_iter().for_each(|(key, val)| { tx_host_env::with(|env| { @@ -785,16 +782,13 @@ mod tests { let msg = ibc::msg_connection_open_try(client_id, client_state); let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair.clone()) + .add_signing_keys(keypairs.clone(), pks_map.clone()) + .build(); // open try a connection with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -823,16 +817,13 @@ mod tests { let msg = ibc::msg_connection_open_confirm(conn_id); let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair) + .add_signing_keys(keypairs, pks_map) + .build(); // open the connection with the mssage tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -849,6 +840,12 @@ mod tests { // The environment must be initialized first tx_host_env::init(); + let keypair = key::testing::keypair_1(); + let keypairs = vec![keypair.clone()]; + let pks_map = AccountPublicKeysMap::from_iter([ + key::testing::keypair_1().ref_to(), + ]); + // Set the initial state before starting transactions ibc::init_storage(); let (client_id, _client_state, mut writes) = ibc::prepare_client(); @@ -868,16 +865,13 @@ mod tests { let msg = ibc::msg_channel_open_init(port_id.clone(), conn_id); let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair.clone()) + .add_signing_keys(keypairs.clone(), pks_map.clone()) + .build(); // init a channel with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -906,16 +900,13 @@ mod tests { let msg = ibc::msg_channel_open_ack(port_id, channel_id); let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair) + .add_signing_keys(keypairs, pks_map) + .build(); // open the channle with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -946,21 +937,24 @@ mod tests { }); }); + let keypair = key::testing::keypair_1(); + let keypairs = vec![keypair.clone()]; + let pks_map = AccountPublicKeysMap::from_iter([ + key::testing::keypair_1().ref_to(), + ]); + // Start a transaction for ChannelOpenTry let port_id = ibc::PortId::transfer(); let msg = ibc::msg_channel_open_try(port_id.clone(), conn_id); let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair.clone()) + .add_signing_keys(keypairs.clone(), pks_map.clone()) + .build(); // try open a channel with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -990,16 +984,13 @@ mod tests { let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair) + .add_signing_keys(keypairs, pks_map) + .build(); // open a channel with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -1033,21 +1024,24 @@ mod tests { }); }); + let keypair = key::testing::keypair_1(); + let keypairs = vec![keypair.clone()]; + let pks_map = AccountPublicKeysMap::from_iter([ + key::testing::keypair_1().ref_to(), + ]); + // Start a transaction to close the channel let msg = ibc::msg_channel_close_init(port_id, channel_id); let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair) + .add_signing_keys(keypairs, pks_map) + .build(); // close the channel with the message let mut actions = tx_host_env::ibc::ibc_actions(tx::ctx()); // the dummy module closes the channel @@ -1089,21 +1083,24 @@ mod tests { }); }); + let keypair = key::testing::keypair_1(); + let keypairs = vec![keypair.clone()]; + let pks_map = AccountPublicKeysMap::from_iter([ + key::testing::keypair_1().ref_to(), + ]); + // Start a transaction to close the channel let msg = ibc::msg_channel_close_confirm(port_id, channel_id); let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair) + .add_signing_keys(keypairs, pks_map) + .build(); // close the channel with the message tx_host_env::ibc::ibc_actions(tx::ctx()) @@ -1138,6 +1135,12 @@ mod tests { }); }); + let keypair = key::testing::keypair_1(); + let keypairs = vec![keypair.clone()]; + let pks_map = AccountPublicKeysMap::from_iter([ + key::testing::keypair_1().ref_to(), + ]); + // Start a transaction to send a packet let msg = ibc::msg_transfer(port_id, channel_id, token.to_string(), &sender); @@ -1147,16 +1150,13 @@ mod tests { .encode(&mut tx_data) .expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair.clone()) + .add_signing_keys(keypairs.clone(), pks_map.clone()) + .build(); // send the token and a packet with the data tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -1199,16 +1199,13 @@ mod tests { let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair) + .add_signing_keys(keypairs, pks_map) + .build(); // ack the packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -1240,6 +1237,12 @@ mod tests { // The environment must be initialized first tx_host_env::init(); + let keypair = key::testing::keypair_1(); + let keypairs = vec![keypair.clone()]; + let pks_map = AccountPublicKeysMap::from_iter([ + key::testing::keypair_1().ref_to(), + ]); + // Set the initial state before starting transactions let (token, sender) = ibc::init_storage(); let (client_id, _client_state, mut writes) = ibc::prepare_client(); @@ -1278,16 +1281,13 @@ mod tests { let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair) + .add_signing_keys(keypairs, pks_map) + .build(); // send the token and a packet with the data tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -1325,6 +1325,12 @@ mod tests { // The environment must be initialized first tx_host_env::init(); + let keypair = key::testing::keypair_1(); + let keypairs = vec![keypair.clone()]; + let pks_map = AccountPublicKeysMap::from_iter([ + key::testing::keypair_1().ref_to(), + ]); + // Set the initial state before starting transactions let (token, receiver) = ibc::init_storage(); let (client_id, _client_state, mut writes) = ibc::prepare_client(); @@ -1357,16 +1363,13 @@ mod tests { let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair) + .add_signing_keys(keypairs, pks_map) + .build(); // receive a packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -1398,6 +1401,12 @@ mod tests { // The environment must be initialized first tx_host_env::init(); + let keypair = key::testing::keypair_1(); + let keypairs = vec![keypair.clone()]; + let pks_map = AccountPublicKeysMap::from_iter([ + key::testing::keypair_1().ref_to(), + ]); + // Set the initial state before starting transactions let (token, receiver) = ibc::init_storage(); let (client_id, _client_state, mut writes) = ibc::prepare_client(); @@ -1448,16 +1457,13 @@ mod tests { let msg = ibc::msg_packet_recv(packet); let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair) + .add_signing_keys(keypairs, pks_map) + .build(); // receive a packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -1488,6 +1494,12 @@ mod tests { // The environment must be initialized first tx_host_env::init(); + let keypair = key::testing::keypair_1(); + let keypairs = vec![keypair.clone()]; + let pks_map = AccountPublicKeysMap::from_iter([ + key::testing::keypair_1().ref_to(), + ]); + // Set the initial state before starting transactions let (token, receiver) = ibc::init_storage(); let (client_id, _client_state, mut writes) = ibc::prepare_client(); @@ -1543,16 +1555,13 @@ mod tests { let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair) + .add_signing_keys(keypairs, pks_map) + .build(); // receive a packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -1586,6 +1595,12 @@ mod tests { // The environment must be initialized first tx_host_env::init(); + let keypair = key::testing::keypair_1(); + let keypairs = vec![keypair.clone()]; + let pks_map = AccountPublicKeysMap::from_iter([ + key::testing::keypair_1().ref_to(), + ]); + // Set the initial state before starting transactions let (token, sender) = ibc::init_storage(); let (client_id, _client_state, mut writes) = ibc::prepare_client(); @@ -1641,16 +1656,13 @@ mod tests { let msg = ibc::msg_timeout(packet, ibc::Sequence::from(1)); let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair) + .add_signing_keys(keypairs, pks_map) + .build(); // timeout the packet tx_host_env::ibc::ibc_actions(tx::ctx()) @@ -1675,6 +1687,12 @@ mod tests { // The environment must be initialized first tx_host_env::init(); + let keypair = key::testing::keypair_1(); + let keypairs = vec![keypair.clone()]; + let pks_map = AccountPublicKeysMap::from_iter([ + key::testing::keypair_1().ref_to(), + ]); + // Set the initial state before starting transactions let (token, sender) = ibc::init_storage(); let (client_id, _client_state, mut writes) = ibc::prepare_client(); @@ -1729,16 +1747,13 @@ mod tests { let msg = ibc::msg_timeout_on_close(packet, ibc::Sequence::from(1)); let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(vec![])); - tx.set_data(Data::new(tx_data.clone())); - tx.add_section(Section::SectionSignature(MultiSignature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &[key::testing::keypair_1()], - &AccountPublicKeysMap::from_iter([ - key::testing::keypair_1().ref_to() - ]), - ))); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .add_fee_payer(keypair) + .add_signing_keys(keypairs, pks_map) + .build(); // timeout the packet tx_host_env::ibc::ibc_actions(tx::ctx()) diff --git a/wasm/checksums.json b/wasm/checksums.json index a86e9c87a8..1a77178f1b 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,22 +1,22 @@ { - "tx_bond.wasm": "tx_bond.5bad50cd6097fd117b0f49b27f001ba07c67f1e62bacac0ad7918592b239c77c.wasm", - "tx_bridge_pool.wasm": "tx_bridge_pool.15c3c6f7d1bc9c00ae9128032a6cad1933f213d1d88537fcd6229aae29dca416.wasm", - "tx_change_validator_commission.wasm": "tx_change_validator_commission.6a3c2ff0c51ca550447cf790fc0936d591f65a9702fdda3886425284c941c31a.wasm", - "tx_ibc.wasm": "tx_ibc.3810b04b25f124baad7f47b1505bc95b878b399a3caa311607317af41739ae3a.wasm", - "tx_init_account.wasm": "tx_init_account.6dddabfa67d2177d444da5edfca8ef45cff6e9bef174bec49293608ba015a491.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.8b38410576dbe474d9880a831368dc229ecfae918d861a9efd8c578e1d05522b.wasm", - "tx_init_validator.wasm": "tx_init_validator.430d6ebc0c477ec7ce628818ff263ccbf4cec92df92904fa939d981461509f77.wasm", - "tx_reveal_pk.wasm": "tx_reveal_pk.f8e15cc1b2792dd51398d5fe20e8fde9a6cbc8502c3bc6fbbae8cf172e3ed434.wasm", - "tx_transfer.wasm": "tx_transfer.72a1719b6dc9fc40c5de61f3bb9215deddf0b0e982cb2f3444c64b5db939d290.wasm", - "tx_unbond.wasm": "tx_unbond.9443fe926e6420a380d994c6640d0abc75fd9ce58f2484f83137e0cde2bc260b.wasm", - "tx_unjail_validator.wasm": "tx_unjail_validator.04dfa8eee97453a15a5864b3bd5f2295201cd8c40ff1d14400d1f44e91566bfe.wasm", - "tx_update_account.wasm": "tx_update_account.8d8ea8f38c001ff4b04f68907ed38251a28eadc78722f61ec2a946273d2a9430.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.d3064c07343ff6d46654887839331d1835dd65e42fef2ca5ac12ae37b30c5ec7.wasm", - "tx_withdraw.wasm": "tx_withdraw.91090e09c191690c8b0a169daaed2bf04bdb75c04c5668017ee2c134d51c895a.wasm", - "vp_implicit.wasm": "vp_implicit.2f55ccc942f156fb46d305af34104ce6d3be02da0d2081217b66a89d5fa19834.wasm", - "vp_masp.wasm": "vp_masp.1dc9def28798be5ad206f01eb80c37764955482c6b0a61da52f0ed5833c86294.wasm", - "vp_testnet_faucet.wasm": "vp_testnet_faucet.f276f01df7081d275e3c1f08d1e5f100c41548f0529f2919ee9e2ed2db53c575.wasm", - "vp_token.wasm": "vp_token.eff25120192554edd4397ddba1d03aacbf7b6839dbf134b24fc804884cc9a4eb.wasm", - "vp_user.wasm": "vp_user.b37170b7ac708ed959214fd11576dc5fb0301f110f6e8c7c9e753c77f4c824c2.wasm", - "vp_validator.wasm": "vp_validator.9cdf33ce7ee86c03c3e2127df4d769d9b69feb69e049d64980f4786d34d08ce9.wasm" + "tx_bond.wasm": "tx_bond.d1aea330d22cedce7f2c4c15a8da5c84e323f743e3932cfb3e9f5cc04067dc0d.wasm", + "tx_bridge_pool.wasm": "tx_bridge_pool.13fbe60b21c37a7122dec49f46d99b383e1eaf2c26a516fdc5b1db1072ce38a7.wasm", + "tx_change_validator_commission.wasm": "tx_change_validator_commission.ddf35f2f9806d84fb3c9997f4760d67ad07b67b61946523960817a3576320e11.wasm", + "tx_ibc.wasm": "tx_ibc.1268bb1eba712d3bf6c90836cc94d0ea31d433441f32d42783df0ae1cca445a7.wasm", + "tx_init_account.wasm": "tx_init_account.bf607cb042cb82b747505d86b6d4367520b0cb3ef78224c2d7664755c1f2728b.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.65e92ec3a841e16a59ee85afe21c0786e94c73ee978f91148a0a0baccd6a73ac.wasm", + "tx_init_validator.wasm": "tx_init_validator.d84ed0638264a5c7a677484f2bc51aa577e44f1a0d5e08fd0ae2e6d11bbabf06.wasm", + "tx_reveal_pk.wasm": "tx_reveal_pk.6f5f2a88ec50fc9bcf77e6127f69ad96fcb95e95c27f2dde7070e0493b589e73.wasm", + "tx_transfer.wasm": "tx_transfer.f4928ca3b4f55d08fee1387e717fabe498c5137af30b51e9f58e84751943ec3d.wasm", + "tx_unbond.wasm": "tx_unbond.e368b03d2e00450c8a5e4f6fcf181d6b53d48b88c1376ecf4d41889e0dd6f267.wasm", + "tx_unjail_validator.wasm": "tx_unjail_validator.0d7a8e680491322f7696cdb48ac00e3b4c1ba936441d5b6eafa73c6ec4a42459.wasm", + "tx_update_account.wasm": "tx_update_account.5d1d852a1ee627f9d493a81947d79c44b420fb27728e8bb6073839eb39099668.wasm", + "tx_vote_proposal.wasm": "tx_vote_proposal.cf63831b4bac30f59fb65c79e6a0d71ed9b69a4c3331cb2cfd6d9cfae3c6f950.wasm", + "tx_withdraw.wasm": "tx_withdraw.820210f1dfcf8de320df453825baaea59eae5f02122808ee60598d8d8ba95633.wasm", + "vp_implicit.wasm": "vp_implicit.3741f7fa68bbc04ecd0521bc9b5915ceccbe48fda899a5fadec8b5315b13fde8.wasm", + "vp_masp.wasm": "vp_masp.8b89b3d4e7da89b96e1b74b5e594988bea9672e47e347bb1b3a2971fb958da6b.wasm", + "vp_testnet_faucet.wasm": "vp_testnet_faucet.fc41c619b6b6fcb96c9b79947e5fc068babb4ec3e29b2dba6ef9a8df835ba58b.wasm", + "vp_token.wasm": "vp_token.142e25ef0f3dc2537a57d3240ca3cc4d58396ae883ebc01ddd15eb4463c11354.wasm", + "vp_user.wasm": "vp_user.a2c7c8d436c5bdfaf4a016fff297c7e574b03ccde75405668525b39a64968df3.wasm", + "vp_validator.wasm": "vp_validator.29dfa6a1e1715e2f96fcfd5462007ab2131b1c0febc0bfe432ae83b944361a71.wasm" } \ No newline at end of file diff --git a/wasm/wasm_source/src/tx_bond.rs b/wasm/wasm_source/src/tx_bond.rs index df55270ceb..1004609744 100644 --- a/wasm/wasm_source/src/tx_bond.rs +++ b/wasm/wasm_source/src/tx_bond.rs @@ -22,10 +22,9 @@ mod tests { bond_handle, read_consensus_validator_set_addresses_with_stake, read_total_stake, read_validator_stake, }; - use namada::proto::{Code, Data, Signature, Tx}; use namada::types::dec::Dec; use namada::types::storage::Epoch; - use namada::types::transaction::TxType; + use namada::types::tx::TxBuilder; use namada_tests::log::test; use namada_tests::native_vp::pos::init_pos; use namada_tests::native_vp::TestNativeVpEnv; @@ -34,6 +33,7 @@ mod tests { arb_established_address, arb_non_internal_address, }; use namada_tx_prelude::address::InternalAddress; + use namada_tx_prelude::chain::ChainId; use namada_tx_prelude::key::testing::arb_common_keypair; use namada_tx_prelude::key::RefTo; use namada_tx_prelude::proof_of_stake::parameters::testing::arb_pos_params; @@ -108,14 +108,14 @@ mod tests { let tx_code = vec![]; let tx_data = bond.try_to_vec().unwrap(); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(tx_code)); - tx.set_data(Data::new(tx_data)); - tx.add_section(Section::Signature(Signature::new( - vec![*tx.data_sechash(), *tx.code_sechash()], - &key, - ))); - let signed_tx = tx.clone(); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(tx_code) + .add_serialized_data(tx_data) + .add_fee_payer(key) + .build(); + + let signed_tx = tx; // Ensure that the initial stake of the sole validator is equal to the // PoS account balance diff --git a/wasm/wasm_source/src/tx_change_validator_commission.rs b/wasm/wasm_source/src/tx_change_validator_commission.rs index edbad6efaa..1877a8f822 100644 --- a/wasm/wasm_source/src/tx_change_validator_commission.rs +++ b/wasm/wasm_source/src/tx_change_validator_commission.rs @@ -21,15 +21,15 @@ mod tests { use namada::ledger::pos::{PosParams, PosVP}; use namada::proof_of_stake::validator_commission_rate_handle; - use namada::proto::{Code, Data, Signature, Tx}; use namada::types::dec::{Dec, POS_DECIMAL_PRECISION}; use namada::types::storage::Epoch; - use namada::types::transaction::TxType; + use namada::types::tx::TxBuilder; use namada_tests::log::test; use namada_tests::native_vp::pos::init_pos; use namada_tests::native_vp::TestNativeVpEnv; use namada_tests::tx::*; use namada_tx_prelude::address::testing::arb_established_address; + use namada_tx_prelude::chain::ChainId; use namada_tx_prelude::key::testing::arb_common_keypair; use namada_tx_prelude::key::RefTo; use namada_tx_prelude::proof_of_stake::parameters::testing::arb_pos_params; @@ -87,14 +87,14 @@ mod tests { let tx_code = vec![]; let tx_data = commission_change.try_to_vec().unwrap(); - let mut tx = Tx::new(TxType::Raw); - tx.set_data(Data::new(tx_data)); - tx.set_code(Code::new(tx_code)); - tx.add_section(Section::Signature(Signature::new( - vec![*tx.data_sechash(), *tx.code_sechash()], - &key, - ))); - let signed_tx = tx.clone(); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(tx_code) + .add_serialized_data(tx_data) + .add_fee_payer(key) + .build(); + + let signed_tx = tx; // Read the data before the tx is executed let commission_rate_handle = diff --git a/wasm/wasm_source/src/tx_unbond.rs b/wasm/wasm_source/src/tx_unbond.rs index 7fb1de8f4f..e41fce38f8 100644 --- a/wasm/wasm_source/src/tx_unbond.rs +++ b/wasm/wasm_source/src/tx_unbond.rs @@ -23,15 +23,15 @@ mod tests { bond_handle, read_consensus_validator_set_addresses_with_stake, read_total_stake, read_validator_stake, unbond_handle, }; - use namada::proto::{Code, Data, Signature, Tx}; use namada::types::dec::Dec; use namada::types::storage::Epoch; - use namada::types::transaction::TxType; + use namada::types::tx::TxBuilder; use namada_tests::log::test; use namada_tests::native_vp::pos::init_pos; use namada_tests::native_vp::TestNativeVpEnv; use namada_tests::tx::*; use namada_tx_prelude::address::InternalAddress; + use namada_tx_prelude::chain::ChainId; use namada_tx_prelude::key::testing::arb_common_keypair; use namada_tx_prelude::key::RefTo; use namada_tx_prelude::proof_of_stake::parameters::testing::arb_pos_params; @@ -132,14 +132,13 @@ mod tests { let tx_code = vec![]; let tx_data = unbond.try_to_vec().unwrap(); - let mut tx = Tx::new(TxType::Raw); - tx.set_data(Data::new(tx_data)); - tx.set_code(Code::new(tx_code)); - tx.add_section(Section::Signature(Signature::new( - vec![*tx.data_sechash(), *tx.code_sechash()], - &key, - ))); - let signed_tx = tx.clone(); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(tx_code) + .add_serialized_data(tx_data) + .add_fee_payer(key) + .build(); + let signed_tx = tx; let unbond_src = unbond .source diff --git a/wasm/wasm_source/src/tx_withdraw.rs b/wasm/wasm_source/src/tx_withdraw.rs index 85ab2b3af4..5622d25c4a 100644 --- a/wasm/wasm_source/src/tx_withdraw.rs +++ b/wasm/wasm_source/src/tx_withdraw.rs @@ -22,10 +22,9 @@ fn apply_tx(ctx: &mut Ctx, tx_data: Tx) -> TxResult { mod tests { use namada::ledger::pos::{GenesisValidator, PosParams, PosVP}; use namada::proof_of_stake::unbond_handle; - use namada::proto::{Code, Data, Signature, Tx}; use namada::types::dec::Dec; use namada::types::storage::Epoch; - use namada::types::transaction::TxType; + use namada::types::tx::TxBuilder; use namada_tests::log::test; use namada_tests::native_vp::pos::init_pos; use namada_tests::native_vp::TestNativeVpEnv; @@ -34,6 +33,7 @@ mod tests { arb_established_address, arb_non_internal_address, }; use namada_tx_prelude::address::InternalAddress; + use namada_tx_prelude::chain::ChainId; use namada_tx_prelude::key::testing::arb_common_keypair; use namada_tx_prelude::key::RefTo; use namada_tx_prelude::proof_of_stake::parameters::testing::arb_pos_params; @@ -176,14 +176,13 @@ mod tests { let tx_code = vec![]; let tx_data = withdraw.try_to_vec().unwrap(); - let mut tx = Tx::new(TxType::Raw); - tx.set_code(Code::new(tx_code)); - tx.set_data(Data::new(tx_data)); - tx.add_section(Section::Signature(Signature::new( - vec![*tx.data_sechash(), *tx.code_sechash()], - &key, - ))); - let signed_tx = tx.clone(); + let tx_builder = TxBuilder::new(ChainId::default(), None); + let tx = tx_builder + .add_code(tx_code) + .add_serialized_data(tx_data) + .add_fee_payer(key) + .build(); + let signed_tx = tx; // Read data before we apply tx: let pos_balance_key = token::balance_key( diff --git a/wasm_for_tests/wasm_source/Cargo.toml b/wasm_for_tests/wasm_source/Cargo.toml index 8d0050f076..ebf94785ea 100644 --- a/wasm_for_tests/wasm_source/Cargo.toml +++ b/wasm_for_tests/wasm_source/Cargo.toml @@ -13,7 +13,6 @@ crate-type = ["cdylib"] # Newly added wasms should also be added into the Makefile `$(wasms)` list. [features] tx_memory_limit = [] -tx_mint_tokens = [] tx_no_op = [] tx_read_storage_key = [] tx_write = [] diff --git a/wasm_for_tests/wasm_source/Makefile b/wasm_for_tests/wasm_source/Makefile index ca46c0b569..f56ab0afb8 100644 --- a/wasm_for_tests/wasm_source/Makefile +++ b/wasm_for_tests/wasm_source/Makefile @@ -6,7 +6,6 @@ nightly := $(shell cat ../../rust-nightly-version) # All the wasms that can be built from this source, switched via Cargo features # Wasms can be added via the Cargo.toml `[features]` list. wasms := tx_memory_limit -wasms += tx_mint_tokens wasms += tx_no_op wasms += tx_read_storage_key wasms += tx_write