From d618365c88963051740f60fee2e0971af91e5412 Mon Sep 17 00:00:00 2001 From: satan Date: Sat, 22 Jul 2023 00:25:58 +0200 Subject: [PATCH 1/9] [feat]: Made sdk and client io generic --- apps/src/bin/namada-client/main.rs | 4 +- apps/src/bin/namada-relayer/main.rs | 4 +- apps/src/bin/namada-wallet/main.rs | 4 +- apps/src/lib/cli.rs | 3 +- apps/src/lib/cli/api.rs | 12 +- apps/src/lib/cli/client.rs | 178 +++-- apps/src/lib/cli/context.rs | 5 +- apps/src/lib/cli/relayer.rs | 43 +- apps/src/lib/cli/utils.rs | 3 +- apps/src/lib/cli/wallet.rs | 252 +++--- apps/src/lib/client/rpc.rs | 751 ++++++++++++------ apps/src/lib/client/signing.rs | 18 +- apps/src/lib/client/tx.rs | 437 ++++++---- shared/src/ledger/eth_bridge.rs | 22 +- shared/src/ledger/eth_bridge/bridge_pool.rs | 144 ++-- shared/src/ledger/eth_bridge/validator_set.rs | 49 +- shared/src/ledger/masp.rs | 46 +- shared/src/ledger/rpc.rs | 83 +- shared/src/ledger/signing.rs | 130 ++- shared/src/ledger/tx.rs | 432 ++++++---- shared/src/types/io.rs | 117 +++ shared/src/types/mod.rs | 1 + tests/src/e2e/ledger_tests.rs | 7 +- 23 files changed, 1813 insertions(+), 932 deletions(-) create mode 100644 shared/src/types/io.rs diff --git a/apps/src/bin/namada-client/main.rs b/apps/src/bin/namada-client/main.rs index a9e1fb4948..9b43ca8f91 100644 --- a/apps/src/bin/namada-client/main.rs +++ b/apps/src/bin/namada-client/main.rs @@ -1,5 +1,5 @@ use color_eyre::eyre::Result; -use namada_apps::cli::api::CliApi; +use namada_apps::cli::api::{CliApi, CliIo}; use namada_apps::facade::tendermint_rpc::HttpClient; use namada_apps::{cli, logging}; use tracing_subscriber::filter::LevelFilter; @@ -13,7 +13,7 @@ async fn main() -> Result<()> { let _log_guard = logging::init_from_env_or(LevelFilter::INFO)?; // run the CLI - CliApi::<()>::handle_client_command::( + CliApi::::handle_client_command::( None, cli::namada_client_cli()?, ) diff --git a/apps/src/bin/namada-relayer/main.rs b/apps/src/bin/namada-relayer/main.rs index 0b314cb9fa..1d7ae94fec 100644 --- a/apps/src/bin/namada-relayer/main.rs +++ b/apps/src/bin/namada-relayer/main.rs @@ -1,6 +1,6 @@ use color_eyre::eyre::Result; use namada::tendermint_rpc::HttpClient; -use namada_apps::cli::api::CliApi; +use namada_apps::cli::api::{CliApi, CliIo}; use namada_apps::{cli, logging}; use tracing_subscriber::filter::LevelFilter; @@ -14,5 +14,5 @@ async fn main() -> Result<()> { let (cmd, _) = cli::namada_relayer_cli()?; // run the CLI - CliApi::<()>::handle_relayer_command::(None, cmd).await + CliApi::::handle_relayer_command::(None, cmd).await } diff --git a/apps/src/bin/namada-wallet/main.rs b/apps/src/bin/namada-wallet/main.rs index 7459234c79..5e94831716 100644 --- a/apps/src/bin/namada-wallet/main.rs +++ b/apps/src/bin/namada-wallet/main.rs @@ -1,10 +1,10 @@ use color_eyre::eyre::Result; use namada_apps::cli; -use namada_apps::cli::api::CliApi; +use namada_apps::cli::api::{CliApi, CliIo}; pub fn main() -> Result<()> { color_eyre::install()?; let (cmd, ctx) = cli::namada_wallet_cli()?; // run the CLI - CliApi::<()>::handle_wallet_command(cmd, ctx) + CliApi::::handle_wallet_command(cmd, ctx) } diff --git a/apps/src/lib/cli.rs b/apps/src/lib/cli.rs index 699a2b7f17..3874cbbe6f 100644 --- a/apps/src/lib/cli.rs +++ b/apps/src/lib/cli.rs @@ -19,6 +19,7 @@ pub use utils::safe_exit; use utils::*; pub use self::context::Context; +use crate::cli::api::CliIo; include!("../../version.rs"); @@ -5044,7 +5045,7 @@ pub fn namada_client_cli() -> Result { let global_args = args::Global::parse(&matches); match cmd { cmds::NamadaClient::WithContext(sub_cmd) => { - let context = Context::new(global_args)?; + let context = Context::new::(global_args)?; Ok(NamadaClient::WithContext(Box::new((sub_cmd, context)))) } cmds::NamadaClient::WithoutContext(sub_cmd) => { diff --git a/apps/src/lib/cli/api.rs b/apps/src/lib/cli/api.rs index c22fe39fd3..c53f277e29 100644 --- a/apps/src/lib/cli/api.rs +++ b/apps/src/lib/cli/api.rs @@ -4,6 +4,7 @@ use namada::ledger::queries::Client; use namada::ledger::rpc::wait_until_node_is_synched; use namada::tendermint_rpc::HttpClient; use namada::types::control_flow::Halt; +use namada::types::io::Io; use tendermint_config::net::Address as TendermintAddress; use crate::client::utils; @@ -12,7 +13,7 @@ use crate::client::utils; #[async_trait::async_trait(?Send)] pub trait CliClient: Client + Sync { fn from_tendermint_address(address: &mut TendermintAddress) -> Self; - async fn wait_until_node_is_synced(&self) -> Halt<()>; + async fn wait_until_node_is_synced(&self) -> Halt<()>; } #[async_trait::async_trait(?Send)] @@ -21,9 +22,12 @@ impl CliClient for HttpClient { HttpClient::new(utils::take_config_address(address)).unwrap() } - async fn wait_until_node_is_synced(&self) -> Halt<()> { - wait_until_node_is_synched(self).await + async fn wait_until_node_is_synced(&self) -> Halt<()> { + wait_until_node_is_synched::<_, IO>(self).await } } -pub struct CliApi(PhantomData); +pub struct CliIo; +impl Io for CliIo {} + +pub struct CliApi(PhantomData); diff --git a/apps/src/lib/cli/client.rs b/apps/src/lib/cli/client.rs index fb7d01559b..e01c07aa46 100644 --- a/apps/src/lib/cli/client.rs +++ b/apps/src/lib/cli/client.rs @@ -2,6 +2,7 @@ use color_eyre::eyre::{eyre, Report, Result}; use namada::ledger::eth_bridge::bridge_pool; use namada::ledger::{signing, tx as sdk_tx}; use namada::types::control_flow::ProceedOrElse; +use namada::types::io::Io; use crate::cli; use crate::cli::api::{CliApi, CliClient}; @@ -13,7 +14,7 @@ fn error() -> Report { eyre!("Fatal error") } -impl CliApi { +impl CliApi { pub async fn handle_client_command( client: Option, cmd: cli::NamadaClient, @@ -34,19 +35,20 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); let dry_run = args.tx.dry_run; - tx::submit_custom(&client, &mut ctx, args).await?; + tx::submit_custom::<_, IO>(&client, &mut ctx, args) + .await?; if !dry_run { crate::wallet::save(&ctx.wallet) .unwrap_or_else(|err| eprintln!("{}", err)); } else { - println!( + IO::println( "Transaction dry run. No addresses have been \ - saved." + saved.", ) } } @@ -57,11 +59,12 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - tx::submit_transfer(&client, ctx, args).await?; + tx::submit_transfer::<_, IO>(&client, ctx, args) + .await?; } Sub::TxIbcTransfer(TxIbcTransfer(mut args)) => { let client = client.unwrap_or_else(|| { @@ -70,11 +73,12 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - tx::submit_ibc_transfer(&client, ctx, args).await?; + tx::submit_ibc_transfer::<_, IO>(&client, ctx, args) + .await?; } Sub::TxUpdateVp(TxUpdateVp(mut args)) => { let client = client.unwrap_or_else(|| { @@ -83,11 +87,12 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - tx::submit_update_vp(&client, &mut ctx, args).await?; + tx::submit_update_vp::<_, IO>(&client, &mut ctx, args) + .await?; } Sub::TxInitAccount(TxInitAccount(mut args)) => { let client = client.unwrap_or_else(|| { @@ -96,20 +101,22 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); let dry_run = args.tx.dry_run; - tx::submit_init_account(&client, &mut ctx, args) - .await?; + tx::submit_init_account::<_, IO>( + &client, &mut ctx, args, + ) + .await?; if !dry_run { crate::wallet::save(&ctx.wallet) .unwrap_or_else(|err| eprintln!("{}", err)); } else { - println!( + IO::println( "Transaction dry run. No addresses have been \ - saved." + saved.", ) } } @@ -120,11 +127,12 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - tx::submit_init_validator(&client, ctx, args).await?; + tx::submit_init_validator::<_, IO>(&client, ctx, args) + .await?; } Sub::TxInitProposal(TxInitProposal(mut args)) => { let client = client.unwrap_or_else(|| { @@ -133,11 +141,12 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - tx::submit_init_proposal(&client, ctx, args).await?; + tx::submit_init_proposal::<_, IO>(&client, ctx, args) + .await?; } Sub::TxVoteProposal(TxVoteProposal(mut args)) => { let client = client.unwrap_or_else(|| { @@ -146,11 +155,12 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - tx::submit_vote_proposal(&client, ctx, args).await?; + tx::submit_vote_proposal::<_, IO>(&client, ctx, args) + .await?; } Sub::TxRevealPk(TxRevealPk(mut args)) => { let client = client.unwrap_or_else(|| { @@ -159,11 +169,12 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - tx::submit_reveal_pk(&client, &mut ctx, args).await?; + tx::submit_reveal_pk::<_, IO>(&client, &mut ctx, args) + .await?; } Sub::Bond(Bond(mut args)) => { let client = client.unwrap_or_else(|| { @@ -172,11 +183,12 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - tx::submit_bond(&client, &mut ctx, args).await?; + tx::submit_bond::<_, IO>(&client, &mut ctx, args) + .await?; } Sub::Unbond(Unbond(mut args)) => { let client = client.unwrap_or_else(|| { @@ -185,11 +197,12 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - tx::submit_unbond(&client, &mut ctx, args).await?; + tx::submit_unbond::<_, IO>(&client, &mut ctx, args) + .await?; } Sub::Withdraw(Withdraw(mut args)) => { let client = client.unwrap_or_else(|| { @@ -198,11 +211,12 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - tx::submit_withdraw(&client, ctx, args).await?; + tx::submit_withdraw::<_, IO>(&client, ctx, args) + .await?; } Sub::TxCommissionRateChange(TxCommissionRateChange( mut args, @@ -213,11 +227,11 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - tx::submit_validator_commission_change( + tx::submit_validator_commission_change::<_, IO>( &client, ctx, args, ) .await?; @@ -231,20 +245,20 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); let tx_args = args.tx.clone(); let (mut tx, addr, pk) = - bridge_pool::build_bridge_pool_tx( + bridge_pool::build_bridge_pool_tx::<_, _, IO>( &client, &mut ctx.wallet, args, ) .await .unwrap(); - tx::submit_reveal_aux( + tx::submit_reveal_aux::<_, IO>( &client, &mut ctx, &tx_args, @@ -260,7 +274,7 @@ impl CliApi { &pk, ) .await?; - sdk_tx::process_tx( + sdk_tx::process_tx::<_, _, IO>( &client, &mut ctx.wallet, &tx_args, @@ -274,10 +288,10 @@ impl CliApi { C::from_tendermint_address(&mut args.ledger_address) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; - rpc::query_and_print_epoch(&client).await; + rpc::query_and_print_epoch::<_, IO>(&client).await; } Sub::QueryTransfers(QueryTransfers(mut args)) => { let client = client.unwrap_or_else(|| { @@ -286,11 +300,11 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - rpc::query_transfers( + rpc::query_transfers::<_, _, IO>( &client, &mut ctx.wallet, &mut ctx.shielded, @@ -305,22 +319,26 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - rpc::query_conversions(&client, &mut ctx.wallet, args) - .await; + rpc::query_conversions::<_, IO>( + &client, + &mut ctx.wallet, + args, + ) + .await; } Sub::QueryBlock(QueryBlock(mut args)) => { let client = client.unwrap_or_else(|| { C::from_tendermint_address(&mut args.ledger_address) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; - rpc::query_block(&client).await; + rpc::query_block::<_, IO>(&client).await; } Sub::QueryBalance(QueryBalance(mut args)) => { let client = client.unwrap_or_else(|| { @@ -329,11 +347,11 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - rpc::query_balance( + rpc::query_balance::<_, _, IO>( &client, &mut ctx.wallet, &mut ctx.shielded, @@ -348,13 +366,17 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - rpc::query_bonds(&client, &mut ctx.wallet, args) - .await - .expect("expected successful query of bonds"); + rpc::query_bonds::<_, IO>( + &client, + &mut ctx.wallet, + args, + ) + .await + .expect("expected successful query of bonds"); } Sub::QueryBondedStake(QueryBondedStake(mut args)) => { let client = client.unwrap_or_else(|| { @@ -363,11 +385,11 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - rpc::query_bonded_stake(&client, args).await; + rpc::query_bonded_stake::<_, IO>(&client, args).await; } Sub::QueryCommissionRate(QueryCommissionRate(mut args)) => { let client = client.unwrap_or_else(|| { @@ -376,11 +398,11 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - rpc::query_and_print_commission_rate( + rpc::query_and_print_commission_rate::<_, IO>( &client, &mut ctx.wallet, args, @@ -394,12 +416,16 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - rpc::query_slashes(&client, &mut ctx.wallet, args) - .await; + rpc::query_slashes::<_, IO>( + &client, + &mut ctx.wallet, + args, + ) + .await; } Sub::QueryDelegations(QueryDelegations(mut args)) => { let client = client.unwrap_or_else(|| { @@ -408,12 +434,16 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - rpc::query_delegations(&client, &mut ctx.wallet, args) - .await; + rpc::query_delegations::<_, IO>( + &client, + &mut ctx.wallet, + args, + ) + .await; } Sub::QueryFindValidator(QueryFindValidator(mut args)) => { let client = client.unwrap_or_else(|| { @@ -422,11 +452,11 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - rpc::query_find_validator(&client, args).await; + rpc::query_find_validator::<_, IO>(&client, args).await; } Sub::QueryResult(QueryResult(mut args)) => { let client = client.unwrap_or_else(|| { @@ -435,11 +465,11 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - rpc::query_result(&client, args).await; + rpc::query_result::<_, IO>(&client, args).await; } Sub::QueryRawBytes(QueryRawBytes(mut args)) => { let client = client.unwrap_or_else(|| { @@ -448,11 +478,11 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - rpc::query_raw_bytes(&client, args).await; + rpc::query_raw_bytes::<_, IO>(&client, args).await; } Sub::QueryProposal(QueryProposal(mut args)) => { @@ -462,11 +492,11 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - rpc::query_proposal(&client, args).await; + rpc::query_proposal::<_, IO>(&client, args).await; } Sub::QueryProposalResult(QueryProposalResult(mut args)) => { let client = client.unwrap_or_else(|| { @@ -475,11 +505,12 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - rpc::query_proposal_result(&client, args).await; + rpc::query_proposal_result::<_, IO>(&client, args) + .await; } Sub::QueryProtocolParameters(QueryProtocolParameters( mut args, @@ -490,11 +521,12 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - rpc::query_protocol_parameters(&client, args).await; + rpc::query_protocol_parameters::<_, IO>(&client, args) + .await; } } } diff --git a/apps/src/lib/cli/context.rs b/apps/src/lib/cli/context.rs index 0622827140..3027976754 100644 --- a/apps/src/lib/cli/context.rs +++ b/apps/src/lib/cli/context.rs @@ -12,6 +12,7 @@ use namada::ledger::wallet::store::AddressVpType; use namada::ledger::wallet::Wallet; use namada::types::address::Address; use namada::types::chain::ChainId; +use namada::types::io::Io; use namada::types::key::*; use namada::types::masp::*; @@ -82,7 +83,7 @@ pub struct Context { } impl Context { - pub fn new(global_args: args::Global) -> Result { + pub fn new(global_args: args::Global) -> Result { let global_config = read_or_try_new_global_config(&global_args); tracing::debug!("Chain ID: {}", global_config.default_chain_id); @@ -124,7 +125,7 @@ impl Context { wallet, global_config, config, - shielded: CLIShieldedUtils::new(chain_dir), + shielded: CLIShieldedUtils::new::(chain_dir), native_token, }) } diff --git a/apps/src/lib/cli/relayer.rs b/apps/src/lib/cli/relayer.rs index 531051d27a..65ec0cf56b 100644 --- a/apps/src/lib/cli/relayer.rs +++ b/apps/src/lib/cli/relayer.rs @@ -4,6 +4,7 @@ use color_eyre::eyre::{eyre, Report, Result}; use namada::eth_bridge::ethers::providers::{Http, Provider}; use namada::ledger::eth_bridge::{bridge_pool, validator_set}; use namada::types::control_flow::ProceedOrElse; +use namada::types::io::Io; use crate::cli::api::{CliApi, CliClient}; use crate::cli::args::CliToSdkCtxless; @@ -13,7 +14,7 @@ fn error() -> Report { eyre!("Fatal error") } -impl CliApi { +impl CliApi { pub async fn handle_relayer_command( client: Option, cmd: cmds::NamadaRelayer, @@ -30,11 +31,11 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk_ctxless(); - bridge_pool::recommend_batch(&client, args) + bridge_pool::recommend_batch::<_, IO>(&client, args) .await .proceed_or_else(error)?; } @@ -45,11 +46,11 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk_ctxless(); - bridge_pool::construct_proof(&client, args) + bridge_pool::construct_proof::<_, IO>(&client, args) .await .proceed_or_else(error)?; } @@ -60,7 +61,7 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let eth_client = Arc::new( @@ -68,7 +69,7 @@ impl CliApi { .unwrap(), ); let args = args.to_sdk_ctxless(); - bridge_pool::relay_bridge_pool_proof( + bridge_pool::relay_bridge_pool_proof::<_, _, IO>( eth_client, &client, args, ) .await @@ -79,20 +80,20 @@ impl CliApi { C::from_tendermint_address(&mut query.ledger_address) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; - bridge_pool::query_bridge_pool(&client).await; + bridge_pool::query_bridge_pool::<_, IO>(&client).await; } cmds::EthBridgePool::QuerySigned(mut query) => { let client = client.unwrap_or_else(|| { C::from_tendermint_address(&mut query.ledger_address) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; - bridge_pool::query_signed_bridge_pool(&client) + bridge_pool::query_signed_bridge_pool::<_, IO>(&client) .await .proceed_or_else(error)?; } @@ -101,10 +102,10 @@ impl CliApi { C::from_tendermint_address(&mut query.ledger_address) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; - bridge_pool::query_relay_progress(&client).await; + bridge_pool::query_relay_progress::<_, IO>(&client).await; } }, cmds::NamadaRelayer::ValidatorSet(sub) => match sub { @@ -115,12 +116,14 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk_ctxless(); - validator_set::query_validator_set_args(&client, args) - .await; + validator_set::query_validator_set_args::<_, IO>( + &client, args, + ) + .await; } cmds::ValidatorSet::ValidatorSetProof(mut args) => { let client = client.unwrap_or_else(|| { @@ -129,11 +132,11 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let args = args.to_sdk_ctxless(); - validator_set::query_validator_set_update_proof( + validator_set::query_validator_set_update_proof::<_, IO>( &client, args, ) .await; @@ -145,7 +148,7 @@ impl CliApi { ) }); client - .wait_until_node_is_synced() + .wait_until_node_is_synced::() .await .proceed_or_else(error)?; let eth_client = Arc::new( @@ -153,7 +156,7 @@ impl CliApi { .unwrap(), ); let args = args.to_sdk_ctxless(); - validator_set::relay_validator_set_update( + validator_set::relay_validator_set_update::<_, _, IO>( eth_client, &client, args, ) .await diff --git a/apps/src/lib/cli/utils.rs b/apps/src/lib/cli/utils.rs index eac233ed28..8a4d1429a5 100644 --- a/apps/src/lib/cli/utils.rs +++ b/apps/src/lib/cli/utils.rs @@ -8,6 +8,7 @@ use color_eyre::eyre::Result; use super::args; use super::context::{Context, FromContext}; +use crate::cli::api::CliIo; // We only use static strings pub type App = clap::Command; @@ -22,7 +23,7 @@ pub trait Cmd: Sized { match Self::parse(&matches) { Some(cmd) => { let global_args = args::Global::parse(&matches); - let context = Context::new(global_args)?; + let context = Context::new::(global_args)?; Ok((cmd, context)) } None => { diff --git a/apps/src/lib/cli/wallet.rs b/apps/src/lib/cli/wallet.rs index 7505c59efe..56a0960db6 100644 --- a/apps/src/lib/cli/wallet.rs +++ b/apps/src/lib/cli/wallet.rs @@ -9,6 +9,7 @@ use itertools::sorted; use masp_primitives::zip32::ExtendedFullViewingKey; use namada::ledger::masp::find_valid_diversifier; use namada::ledger::wallet::{DecryptionError, FindKeyError}; +use namada::types::io::Io; use namada::types::key::*; use namada::types::masp::{MaspValue, PaymentAddress}; use rand_core::OsRng; @@ -19,7 +20,7 @@ use crate::cli::args::CliToSdk; use crate::cli::{args, cmds, Context}; use crate::wallet::{read_and_confirm_encryption_password, CliWalletUtils}; -impl CliApi { +impl CliApi { pub fn handle_wallet_command( cmd: cmds::NamadaWallet, mut ctx: Context, @@ -27,57 +28,57 @@ impl CliApi { match cmd { cmds::NamadaWallet::Key(sub) => match sub { cmds::WalletKey::Restore(cmds::KeyRestore(args)) => { - key_and_address_restore(ctx, args) + key_and_address_restore::(ctx, args) } cmds::WalletKey::Gen(cmds::KeyGen(args)) => { - key_and_address_gen(ctx, args) + key_and_address_gen::(ctx, args) } cmds::WalletKey::Find(cmds::KeyFind(args)) => { - key_find(ctx, args) + key_find::(ctx, args) } cmds::WalletKey::List(cmds::KeyList(args)) => { - key_list(ctx, args) + key_list::(ctx, args) } cmds::WalletKey::Export(cmds::Export(args)) => { - key_export(ctx, args) + key_export::(ctx, args) } }, cmds::NamadaWallet::Address(sub) => match sub { cmds::WalletAddress::Gen(cmds::AddressGen(args)) => { - key_and_address_gen(ctx, args) + key_and_address_gen::(ctx, args) } cmds::WalletAddress::Restore(cmds::AddressRestore(args)) => { - key_and_address_restore(ctx, args) + key_and_address_restore::(ctx, args) } cmds::WalletAddress::Find(cmds::AddressOrAliasFind(args)) => { - address_or_alias_find(ctx, args) + address_or_alias_find::(ctx, args) } cmds::WalletAddress::List(cmds::AddressList) => { - address_list(ctx) + address_list::(ctx) } cmds::WalletAddress::Add(cmds::AddressAdd(args)) => { - address_add(ctx, args) + address_add::(ctx, args) } }, cmds::NamadaWallet::Masp(sub) => match sub { cmds::WalletMasp::GenSpendKey(cmds::MaspGenSpendKey(args)) => { - spending_key_gen(ctx, args) + spending_key_gen::(ctx, args) } cmds::WalletMasp::GenPayAddr(cmds::MaspGenPayAddr(args)) => { let args = args.to_sdk(&mut ctx); - payment_address_gen(ctx, args) + payment_address_gen::(ctx, args) } cmds::WalletMasp::AddAddrKey(cmds::MaspAddAddrKey(args)) => { - address_key_add(ctx, args) + address_key_add::(ctx, args) } cmds::WalletMasp::ListPayAddrs(cmds::MaspListPayAddrs) => { - payment_addresses_list(ctx) + payment_addresses_list::(ctx) } cmds::WalletMasp::ListKeys(cmds::MaspListKeys(args)) => { - spending_keys_list(ctx, args) + spending_keys_list::(ctx, args) } cmds::WalletMasp::FindAddrKey(cmds::MaspFindAddrKey(args)) => { - address_key_find(ctx, args) + address_key_find::(ctx, args) } }, } @@ -86,7 +87,7 @@ impl CliApi { } /// Find shielded address or key -fn address_key_find( +fn address_key_find( ctx: Context, args::AddrKeyFind { alias, @@ -97,31 +98,33 @@ fn address_key_find( let alias = alias.to_lowercase(); if let Ok(viewing_key) = wallet.find_viewing_key(&alias) { // Check if alias is a viewing key - println!("Viewing key: {}", viewing_key); + IO::println(format!("Viewing key: {}", viewing_key)); if unsafe_show_secret { // Check if alias is also a spending key match wallet.find_spending_key(&alias, None) { - Ok(spending_key) => println!("Spending key: {}", spending_key), + Ok(spending_key) => { + IO::println(format!("Spending key: {}", spending_key)) + } Err(FindKeyError::KeyNotFound) => {} - Err(err) => eprintln!("{}", err), + Err(err) => IO::eprintln(format!("{}", err)), } } } else if let Some(payment_addr) = wallet.find_payment_addr(&alias) { // Failing that, check if alias is a payment address - println!("Payment address: {}", payment_addr); + IO::println(format!("Payment address: {}", payment_addr)); } else { // Otherwise alias cannot be referring to any shielded value - println!( + IO::println(format!( "No shielded address or key with alias {} found. Use the commands \ `masp list-addrs` and `masp list-keys` to see all the known \ addresses and keys.", alias.to_lowercase() - ); + )); } } /// List spending keys. -fn spending_keys_list( +fn spending_keys_list( ctx: Context, args::MaspKeysList { decrypt, @@ -132,32 +135,32 @@ fn spending_keys_list( let known_view_keys = wallet.get_viewing_keys(); let known_spend_keys = wallet.get_spending_keys(); if known_view_keys.is_empty() { - println!( + IO::println( "No known keys. Try `masp add --alias my-addr --value ...` to add \ - a new key to the wallet." + a new key to the wallet.", ); } else { let stdout = io::stdout(); let mut w = stdout.lock(); - writeln!(w, "Known keys:").unwrap(); + IO::writeln(&mut w, "Known keys:").unwrap(); for (alias, key) in known_view_keys { - write!(w, " Alias \"{}\"", alias).unwrap(); + IO::write(&mut w, format!(" Alias \"{}\"", alias)).unwrap(); let spending_key_opt = known_spend_keys.get(&alias); // If this alias is associated with a spending key, indicate whether // or not the spending key is encrypted // TODO: consider turning if let into match if let Some(spending_key) = spending_key_opt { if spending_key.is_encrypted() { - writeln!(w, " (encrypted):") + IO::writeln(&mut w, " (encrypted):") } else { - writeln!(w, " (not encrypted):") + IO::writeln(&mut w, " (not encrypted):") } .unwrap(); } else { - writeln!(w, ":").unwrap(); + IO::writeln(&mut w, ":").unwrap(); } // Always print the corresponding viewing key - writeln!(w, " Viewing Key: {}", key).unwrap(); + IO::writeln(&mut w, format!(" Viewing Key: {}", key)).unwrap(); // A subset of viewing keys will have corresponding spending keys. // Print those too if they are available and requested. if unsafe_show_secret { @@ -166,8 +169,11 @@ fn spending_keys_list( // Here the spending key is unencrypted or successfully // decrypted Ok(spending_key) => { - writeln!(w, " Spending key: {}", spending_key) - .unwrap(); + IO::writeln( + &mut w, + format!(" Spending key: {}", spending_key), + ) + .unwrap(); } // Here the key is encrypted but decryption has not been // requested @@ -177,10 +183,12 @@ fn spending_keys_list( // Here the key is encrypted but incorrect password has // been provided Err(err) => { - writeln!( - w, - " Couldn't decrypt the spending key: {}", - err + IO::writeln( + &mut w, + format!( + " Couldn't decrypt the spending key: {}", + err + ), ) .unwrap(); } @@ -192,26 +200,27 @@ fn spending_keys_list( } /// List payment addresses. -fn payment_addresses_list(ctx: Context) { +fn payment_addresses_list(ctx: Context) { let wallet = ctx.wallet; let known_addresses = wallet.get_payment_addrs(); if known_addresses.is_empty() { - println!( + IO::println( "No known payment addresses. Try `masp gen-addr --alias my-addr` \ - to generate a new payment address." + to generate a new payment address.", ); } else { let stdout = io::stdout(); let mut w = stdout.lock(); - writeln!(w, "Known payment addresses:").unwrap(); + IO::writeln(&mut w, "Known payment addresses:").unwrap(); for (alias, address) in sorted(known_addresses) { - writeln!(w, " \"{}\": {}", alias, address).unwrap(); + IO::writeln(&mut w, format!(" \"{}\": {}", alias, address)) + .unwrap(); } } } /// Generate a spending key. -fn spending_key_gen( +fn spending_key_gen( ctx: Context, args::MaspSpendKeyGen { alias, @@ -224,14 +233,14 @@ fn spending_key_gen( let password = read_and_confirm_encryption_password(unsafe_dont_encrypt); let (alias, _key) = wallet.gen_spending_key(alias, password, alias_force); crate::wallet::save(&wallet).unwrap_or_else(|err| eprintln!("{}", err)); - println!( + IO::println(format!( "Successfully added a spending key with alias: \"{}\"", alias - ); + )); } /// Generate a shielded payment address from the given key. -fn payment_address_gen( +fn payment_address_gen( ctx: Context, args::MaspPayAddrGen { alias, @@ -254,18 +263,18 @@ fn payment_address_gen( alias_force, ) .unwrap_or_else(|| { - eprintln!("Payment address not added"); + IO::eprintln("Payment address not added"); cli::safe_exit(1); }); crate::wallet::save(&wallet).unwrap_or_else(|err| eprintln!("{}", err)); - println!( + IO::println(format!( "Successfully generated a payment address with the following alias: {}", alias, - ); + )); } /// Add a viewing key, spending key, or payment address to wallet. -fn address_key_add( +fn address_key_add( mut ctx: Context, args::MaspAddrKeyAdd { alias, @@ -281,7 +290,7 @@ fn address_key_add( .wallet .insert_viewing_key(alias, viewing_key, alias_force) .unwrap_or_else(|| { - eprintln!("Viewing key not added"); + IO::eprintln("Viewing key not added"); cli::safe_exit(1); }); (alias, "viewing key") @@ -298,7 +307,7 @@ fn address_key_add( alias_force, ) .unwrap_or_else(|| { - eprintln!("Spending key not added"); + IO::eprintln("Spending key not added"); cli::safe_exit(1); }); (alias, "spending key") @@ -308,22 +317,22 @@ fn address_key_add( .wallet .insert_payment_addr(alias, payment_addr, alias_force) .unwrap_or_else(|| { - eprintln!("Payment address not added"); + IO::eprintln("Payment address not added"); cli::safe_exit(1); }); (alias, "payment address") } }; crate::wallet::save(&ctx.wallet).unwrap_or_else(|err| eprintln!("{}", err)); - println!( + IO::println(format!( "Successfully added a {} with the following alias to wallet: {}", typ, alias, - ); + )); } /// Restore a keypair and an implicit address from the mnemonic code in the /// wallet. -fn key_and_address_restore( +fn key_and_address_restore( ctx: Context, args::KeyAndAddressRestore { scheme, @@ -345,23 +354,24 @@ fn key_and_address_restore( encryption_password, ) .unwrap_or_else(|err| { - eprintln!("{}", err); + IO::eprintln(format!("{}", err)); cli::safe_exit(1) }) .unwrap_or_else(|| { - println!("No changes are persisted. Exiting."); + IO::println("No changes are persisted. Exiting."); cli::safe_exit(0); }); - crate::wallet::save(&wallet).unwrap_or_else(|err| eprintln!("{}", err)); - println!( + crate::wallet::save(&wallet) + .unwrap_or_else(|err| IO::eprintln(format!("{}", err))); + IO::println(format!( "Successfully added a key and an address with alias: \"{}\"", alias - ); + )); } /// Generate a new keypair and derive implicit address from it and store them in /// the wallet. -fn key_and_address_gen( +fn key_and_address_gen( ctx: Context, args::KeyAndAddressGen { scheme, @@ -386,22 +396,23 @@ fn key_and_address_gen( derivation_path_and_mnemonic_rng, ) .unwrap_or_else(|err| { - eprintln!("{}", err); + IO::eprintln(format!("{}", err)); cli::safe_exit(1); }) .unwrap_or_else(|| { - println!("No changes are persisted. Exiting."); + IO::println("No changes are persisted. Exiting."); cli::safe_exit(0); }); - crate::wallet::save(&wallet).unwrap_or_else(|err| eprintln!("{}", err)); - println!( + crate::wallet::save(&wallet) + .unwrap_or_else(|err| IO::eprintln(format!("{}", err))); + IO::println(format!( "Successfully added a key and an address with alias: \"{}\"", alias - ); + )); } /// Find a keypair in the wallet store. -fn key_find( +fn key_find( ctx: Context, args::KeyFind { public_key, @@ -417,9 +428,9 @@ fn key_find( let alias = alias.or(value); match alias { None => { - eprintln!( + IO::eprintln( "An alias, public key or public key hash needs to be \ - supplied" + supplied", ); cli::safe_exit(1) } @@ -430,20 +441,20 @@ fn key_find( match found_keypair { Ok(keypair) => { let pkh: PublicKeyHash = (&keypair.ref_to()).into(); - println!("Public key hash: {}", pkh); - println!("Public key: {}", keypair.ref_to()); + IO::println(format!("Public key hash: {}", pkh)); + IO::println(format!("Public key: {}", keypair.ref_to())); if unsafe_show_secret { - println!("Secret key: {}", keypair); + IO::println(format!("Secret key: {}", keypair)); } } Err(err) => { - eprintln!("{}", err); + IO::eprintln(format!("{}", err)); } } } /// List all known keys. -fn key_list( +fn key_list( ctx: Context, args::KeyList { decrypt, @@ -453,38 +464,53 @@ fn key_list( let wallet = ctx.wallet; let known_keys = wallet.get_keys(); if known_keys.is_empty() { - println!( + IO::println( "No known keys. Try `key gen --alias my-key` to generate a new \ - key." + key.", ); } else { let stdout = io::stdout(); let mut w = stdout.lock(); - writeln!(w, "Known keys:").unwrap(); + IO::writeln(&mut w, "Known keys:").unwrap(); for (alias, (stored_keypair, pkh)) in known_keys { let encrypted = if stored_keypair.is_encrypted() { "encrypted" } else { "not encrypted" }; - writeln!(w, " Alias \"{}\" ({}):", alias, encrypted).unwrap(); + IO::writeln( + &mut w, + format!(" Alias \"{}\" ({}):", alias, encrypted), + ) + .unwrap(); if let Some(pkh) = pkh { - writeln!(w, " Public key hash: {}", pkh).unwrap(); + IO::writeln(&mut w, format!(" Public key hash: {}", pkh)) + .unwrap(); } match stored_keypair.get::(decrypt, None) { Ok(keypair) => { - writeln!(w, " Public key: {}", keypair.ref_to()) - .unwrap(); + IO::writeln( + &mut w, + format!(" Public key: {}", keypair.ref_to()), + ) + .unwrap(); if unsafe_show_secret { - writeln!(w, " Secret key: {}", keypair).unwrap(); + IO::writeln( + &mut w, + format!(" Secret key: {}", keypair), + ) + .unwrap(); } } Err(DecryptionError::NotDecrypting) if !decrypt => { continue; } Err(err) => { - writeln!(w, " Couldn't decrypt the keypair: {}", err) - .unwrap(); + IO::writeln( + &mut w, + format!(" Couldn't decrypt the keypair: {}", err), + ) + .unwrap(); } } } @@ -492,7 +518,10 @@ fn key_list( } /// Export a keypair to a file. -fn key_export(ctx: Context, args::KeyExport { alias }: args::KeyExport) { +fn key_export( + ctx: Context, + args::KeyExport { alias }: args::KeyExport, +) { let mut wallet = ctx.wallet; wallet .find_key(alias.to_lowercase(), None) @@ -504,36 +533,39 @@ fn key_export(ctx: Context, args::KeyExport { alias }: args::KeyExport) { let mut file = File::create(&file_name).unwrap(); file.write_all(file_data.as_ref()).unwrap(); - println!("Exported to file {}", file_name); + IO::println(format!("Exported to file {}", file_name)); }) .unwrap_or_else(|err| { - eprintln!("{}", err); + IO::eprintln(format!("{}", err)); cli::safe_exit(1) }) } /// List all known addresses. -fn address_list(ctx: Context) { +fn address_list(ctx: Context) { let wallet = ctx.wallet; let known_addresses = wallet.get_addresses(); if known_addresses.is_empty() { - println!( + IO::println( "No known addresses. Try `address gen --alias my-addr` to \ - generate a new implicit address." + generate a new implicit address.", ); } else { let stdout = io::stdout(); let mut w = stdout.lock(); - writeln!(w, "Known addresses:").unwrap(); + IO::writeln(&mut w, "Known addresses:").unwrap(); for (alias, address) in sorted(known_addresses) { - writeln!(w, " \"{}\": {}", alias, address.to_pretty_string()) - .unwrap(); + IO::writeln( + &mut w, + format!(" \"{}\": {}", alias, address.to_pretty_string()), + ) + .unwrap(); } } } /// Find address (alias) by its alias (address). -fn address_or_alias_find(ctx: Context, args: args::AddressOrAliasFind) { +fn address_or_alias_find(ctx: Context, args: args::AddressOrAliasFind) { let wallet = ctx.wallet; if args.address.is_some() && args.alias.is_some() { panic!( @@ -543,29 +575,32 @@ fn address_or_alias_find(ctx: Context, args: args::AddressOrAliasFind) { } else if args.alias.is_some() { if let Some(address) = wallet.find_address(args.alias.as_ref().unwrap()) { - println!("Found address {}", address.to_pretty_string()); + IO::println(format!( + "Found address {}", + address.to_pretty_string() + )); } else { - println!( + IO::println(format!( "No address with alias {} found. Use the command `address \ list` to see all the known addresses.", args.alias.unwrap().to_lowercase() - ); + )); } } else if args.address.is_some() { if let Some(alias) = wallet.find_alias(args.address.as_ref().unwrap()) { - println!("Found alias {}", alias); + IO::println(format!("Found alias {}", alias)); } else { - println!( + IO::println(format!( "No alias with address {} found. Use the command `address \ list` to see all the known addresses.", args.address.unwrap() - ); + )); } } } /// Add an address to the wallet. -fn address_add(ctx: Context, args: args::AddressAdd) { +fn address_add(ctx: Context, args: args::AddressAdd) { let mut wallet = ctx.wallet; if wallet .add_address( @@ -575,12 +610,13 @@ fn address_add(ctx: Context, args: args::AddressAdd) { ) .is_none() { - eprintln!("Address not added"); + IO::eprintln("Address not added"); cli::safe_exit(1); } - crate::wallet::save(&wallet).unwrap_or_else(|err| eprintln!("{}", err)); - println!( + crate::wallet::save(&wallet) + .unwrap_or_else(|err| IO::eprintln(format!("{}", err))); + IO::println(format!( "Successfully added a key and an address with alias: \"{}\"", args.alias.to_lowercase() - ); + )); } diff --git a/apps/src/lib/client/rpc.rs b/apps/src/lib/client/rpc.rs index a2d2ffbd50..730b935b46 100644 --- a/apps/src/lib/client/rpc.rs +++ b/apps/src/lib/client/rpc.rs @@ -43,11 +43,13 @@ use namada::types::governance::{ OfflineProposal, OfflineVote, ProposalVote, VotePower, VoteType, }; use namada::types::hash::Hash; +use namada::types::io::Io; use namada::types::key::*; use namada::types::masp::{BalanceOwner, ExtendedViewingKey, PaymentAddress}; use namada::types::storage::{BlockHeight, BlockResults, Epoch, Key, KeySeg}; use namada::types::token::{Change, Denomination, MaspDenom, TokenAddress}; use namada::types::{storage, token}; +use namada::{display, display_line, edisplay}; use tokio::time::Instant; use crate::cli::{self, args}; @@ -59,12 +61,15 @@ use crate::wallet::CliWalletUtils; /// /// If a response is not delivered until `deadline`, we exit the cli with an /// error. -pub async fn query_tx_status( +pub async fn query_tx_status< + C: namada::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, status: namada::ledger::rpc::TxEventQuery<'_>, deadline: Instant, ) -> Event { - namada::ledger::rpc::query_tx_status(client, status, deadline) + namada::ledger::rpc::query_tx_status::<_, IO>(client, status, deadline) .await .proceed() } @@ -72,28 +77,32 @@ pub async fn query_tx_status( /// Query and print the epoch of the last committed block pub async fn query_and_print_epoch< C: namada::ledger::queries::Client + Sync, + IO: Io, >( client: &C, ) -> Epoch { let epoch = namada::ledger::rpc::query_epoch(client).await; - println!("Last committed epoch: {}", epoch); + display_line!(IO, "Last committed epoch: {}", epoch); epoch } /// Query the last committed block -pub async fn query_block( +pub async fn query_block( client: &C, ) { let block = namada::ledger::rpc::query_block(client).await; match block { Some(block) => { - println!( + display_line!( + IO, "Last committed block ID: {}, height: {}, time: {}", - block.hash, block.height, block.time + block.hash, + block.height, + block.time ); } None => { - println!("No block has been committed yet."); + display_line!(IO, "No block has been committed yet."); } } } @@ -112,6 +121,7 @@ pub async fn query_results( pub async fn query_transfers< C: namada::ledger::queries::Client + Sync, U: ShieldedUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -159,7 +169,7 @@ pub async fn query_transfers< // Realize the rewards that would have been attained upon the // transaction's reception let amt = shielded - .compute_exchanged_amount( + .compute_exchanged_amount::<_, IO>( client, amt, epoch, @@ -191,33 +201,43 @@ pub async fn query_transfers< if !relevant { continue; } - println!("Height: {}, Index: {}, Transparent Transfer:", height, idx); + display_line!( + IO, + "Height: {}, Index: {}, Transparent Transfer:", + height, + idx + ); // Display the transparent changes first for (account, MaspChange { ref asset, change }) in tfer_delta { if account != masp() { - print!(" {}:", account); + display!(IO, " {}:", account); let token_alias = lookup_alias(wallet, &asset.address); let sign = match change.cmp(&Change::zero()) { Ordering::Greater => "+", Ordering::Less => "-", Ordering::Equal => "", }; - print!( + display!( + IO, " {}{} {}", sign, - format_denominated_amount(client, asset, change.into(),) - .await, + format_denominated_amount::<_, IO>( + client, + asset, + change.into(), + ) + .await, asset.format_with_alias(&token_alias) ); } - println!(); + display_line!(IO, ""); } // Then display the shielded changes afterwards // TODO: turn this to a display impl // (account, amt) for (account, masp_change) in shielded_accounts { if fvk_map.contains_key(&account) { - print!(" {}:", fvk_map[&account]); + display!(IO, " {}:", fvk_map[&account]); for (token_addr, val) in masp_change { let token_alias = lookup_alias(wallet, &token_addr.address); let sign = match val.cmp(&Change::zero()) { @@ -225,10 +245,11 @@ pub async fn query_transfers< Ordering::Less => "-", Ordering::Equal => "", }; - print!( + display!( + IO, " {}{} {}", sign, - format_denominated_amount( + format_denominated_amount::<_, IO>( client, &token_addr, val.into(), @@ -237,14 +258,17 @@ pub async fn query_transfers< token_addr.format_with_alias(&token_alias), ); } - println!(); + display_line!(IO, ""); } } } } /// Query the raw bytes of given storage key -pub async fn query_raw_bytes( +pub async fn query_raw_bytes< + C: namada::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, args: args::QueryRawBytes, ) { @@ -254,9 +278,9 @@ pub async fn query_raw_bytes( .await, ); if !response.data.is_empty() { - println!("Found data: 0x{}", HEXLOWER.encode(&response.data)); + display_line!(IO, "Found data: 0x{}", HEXLOWER.encode(&response.data)); } else { - println!("No data found for key {}", args.storage_key); + display_line!(IO, "No data found for key {}", args.storage_key); } } @@ -264,6 +288,7 @@ pub async fn query_raw_bytes( pub async fn query_balance< C: namada::ledger::queries::Client + Sync, U: ShieldedUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -274,22 +299,35 @@ pub async fn query_balance< // the CLI arguments match &args.owner { Some(BalanceOwner::FullViewingKey(_viewing_key)) => { - query_shielded_balance(client, wallet, shielded, args).await + query_shielded_balance::<_, _, IO>(client, wallet, shielded, args) + .await } Some(BalanceOwner::Address(_owner)) => { - query_transparent_balance(client, wallet, args).await + query_transparent_balance::<_, IO>(client, wallet, args).await } Some(BalanceOwner::PaymentAddress(_owner)) => { - query_pinned_balance(client, wallet, shielded, args).await + query_pinned_balance::<_, _, IO>(client, wallet, shielded, args) + .await } None => { // Print pinned balance - query_pinned_balance(client, wallet, shielded, args.clone()).await; + query_pinned_balance::<_, _, IO>( + client, + wallet, + shielded, + args.clone(), + ) + .await; // Print shielded balance - query_shielded_balance(client, wallet, shielded, args.clone()) - .await; + query_shielded_balance::<_, _, IO>( + client, + wallet, + shielded, + args.clone(), + ) + .await; // Then print transparent balance - query_transparent_balance(client, wallet, args).await; + query_transparent_balance::<_, IO>(client, wallet, args).await; } }; } @@ -297,6 +335,7 @@ pub async fn query_balance< /// Query token balance(s) pub async fn query_transparent_balance< C: namada::ledger::queries::Client + Sync, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -328,7 +367,7 @@ pub async fn query_transparent_balance< .await { Some(balance) => { - let balance = format_denominated_amount( + let balance = format_denominated_amount::<_, IO>( client, &TokenAddress { address: token, @@ -339,16 +378,26 @@ pub async fn query_transparent_balance< .await; match &args.sub_prefix { Some(sub_prefix) => { - println!( + display_line!( + IO, "{} with {}: {}", - token_alias, sub_prefix, balance + token_alias, + sub_prefix, + balance ); } - None => println!("{}: {}", token_alias, balance), + None => { + display_line!(IO, "{}: {}", token_alias, balance) + } } } None => { - println!("No {} balance found for {}", token_alias, owner) + display_line!( + IO, + "No {} balance found for {}", + token_alias, + owner + ); } } } @@ -356,11 +405,12 @@ pub async fn query_transparent_balance< for token in tokens { let prefix = token::balance_key(&token, &owner.address().unwrap()); - let balances = - query_storage_prefix::(client, &prefix) - .await; + let balances = query_storage_prefix::( + client, &prefix, + ) + .await; if let Some(balances) = balances { - print_balances( + print_balances::<_, IO>( client, wallet, balances, @@ -374,20 +424,24 @@ pub async fn query_transparent_balance< (Some(token), None) => { let prefix = token::balance_prefix(&token); let balances = - query_storage_prefix::(client, &prefix).await; + query_storage_prefix::(client, &prefix) + .await; if let Some(balances) = balances { - print_balances(client, wallet, balances, &token, None).await; + print_balances::<_, IO>(client, wallet, balances, &token, None) + .await; } } (None, None) => { for token in tokens { let key = token::balance_prefix(&token); let balances = - query_storage_prefix::(client, &key) + query_storage_prefix::(client, &key) .await; if let Some(balances) = balances { - print_balances(client, wallet, balances, &token, None) - .await; + print_balances::<_, IO>( + client, wallet, balances, &token, None, + ) + .await; } } } @@ -398,6 +452,7 @@ pub async fn query_transparent_balance< pub async fn query_pinned_balance< C: namada::ledger::queries::Client + Sync, U: ShieldedUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -431,7 +486,7 @@ pub async fn query_pinned_balance< // address for vk in &viewing_keys { balance = shielded - .compute_exchanged_pinned_balance(client, owner, vk) + .compute_exchanged_pinned_balance::<_, IO>(client, owner, vk) .await; if balance != pinned_error { break; @@ -439,32 +494,39 @@ pub async fn query_pinned_balance< } // If a suitable viewing key was not found, then demand it from the user if balance == pinned_error { - print!("Enter the viewing key for {}: ", owner); + display!(IO, "Enter the viewing key for {}: ", owner); io::stdout().flush().unwrap(); let mut vk_str = String::new(); io::stdin().read_line(&mut vk_str).unwrap(); let fvk = match ExtendedViewingKey::from_str(vk_str.trim()) { Ok(fvk) => fvk, _ => { - eprintln!("Invalid viewing key entered"); + edisplay!(IO, "Invalid viewing key entered"); continue; } }; let vk = ExtendedFullViewingKey::from(fvk).fvk.vk; // Use the given viewing key to decrypt pinned transaction data balance = shielded - .compute_exchanged_pinned_balance(client, owner, &vk) + .compute_exchanged_pinned_balance::<_, IO>(client, owner, &vk) .await } // Now print out the received quantities according to CLI arguments match (balance, args.token.as_ref(), args.sub_prefix.as_ref()) { - (Err(PinnedBalanceError::InvalidViewingKey), _, _) => println!( - "Supplied viewing key cannot decode transactions to given \ - payment address." - ), + (Err(PinnedBalanceError::InvalidViewingKey), _, _) => { + display_line!( + IO, + "Supplied viewing key cannot decode transactions to given \ + payment address." + ) + } (Err(PinnedBalanceError::NoTransactionPinned), _, _) => { - println!("Payment address {} has not yet been consumed.", owner) + display_line!( + IO, + "Payment address {} has not yet been consumed.", + owner + ); } (Ok((balance, epoch)), Some(token), sub_prefix) => { let token_alias = lookup_alias(wallet, token); @@ -480,7 +542,8 @@ pub async fn query_pinned_balance< .unwrap_or_default(); if total_balance.is_zero() { - println!( + display_line!( + IO, "Payment address {} was consumed during epoch {}. \ Received no shielded {}", owner, @@ -488,13 +551,14 @@ pub async fn query_pinned_balance< token_address.format_with_alias(&token_alias) ); } else { - let formatted = format_denominated_amount( + let formatted = format_denominated_amount::<_, IO>( client, &token_address, total_balance.into(), ) .await; - println!( + display_line!( + IO, "Payment address {} was consumed during epoch {}. \ Received {} {}", owner, @@ -512,14 +576,16 @@ pub async fn query_pinned_balance< .filter(|((token_epoch, _), _)| *token_epoch == epoch) { if !found_any { - println!( + display_line!( + IO, "Payment address {} was consumed during epoch {}. \ Received:", - owner, epoch + owner, + epoch ); found_any = true; } - let formatted = format_denominated_amount( + let formatted = format_denominated_amount::<_, IO>( client, token_addr, (*value).into(), @@ -529,17 +595,20 @@ pub async fn query_pinned_balance< .get(&token_addr.address) .map(|a| a.to_string()) .unwrap_or_else(|| token_addr.address.to_string()); - println!( + display_line!( + IO, " {}: {}", token_addr.format_with_alias(&token_alias), formatted, ); } if !found_any { - println!( + display_line!( + IO, "Payment address {} was consumed during epoch {}. \ Received no shielded assets.", - owner, epoch + owner, + epoch ); } } @@ -547,7 +616,7 @@ pub async fn query_pinned_balance< } } -async fn print_balances( +async fn print_balances( client: &C, wallet: &Wallet, balances: impl Iterator, @@ -558,7 +627,7 @@ async fn print_balances( let mut w = stdout.lock(); let token_alias = lookup_alias(wallet, token); - writeln!(w, "Token {}", token_alias).unwrap(); + display_line!(IO, &mut w; "Token {}", token_alias).unwrap(); let mut print_num = 0; for (key, balance) in balances { let (o, s) = match token::is_any_multitoken_balance_key(&key) { @@ -567,7 +636,7 @@ async fn print_balances( format!( "with {}: {}, owned by {}", sub_prefix.clone(), - format_denominated_amount( + format_denominated_amount::<_, IO>( client, &TokenAddress { address: tok.clone(), @@ -587,7 +656,7 @@ async fn print_balances( owner.clone(), format!( ": {}, owned by {}", - format_denominated_amount( + format_denominated_amount::<_, IO>( client, &TokenAddress { address: tok.clone(), @@ -609,29 +678,35 @@ async fn print_balances( Some(_) => continue, None => s, }; - writeln!(w, "{}", s).unwrap(); + display_line!(IO, &mut w; "{}", s).unwrap(); print_num += 1; } if print_num == 0 { match target { Some(t) => { - writeln!(w, "No balances owned by {}", lookup_alias(wallet, t)) + display_line!(IO, &mut w; "No balances owned by {}", lookup_alias(wallet, t)) .unwrap() } None => { - writeln!(w, "No balances for token {}", token_alias).unwrap() + display_line!(IO, &mut w; "No balances for token {}", token_alias).unwrap() } } } } /// Query Proposals -pub async fn query_proposal( +pub async fn query_proposal< + C: namada::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, args: args::QueryProposal, ) { - async fn print_proposal( + async fn print_proposal< + C: namada::ledger::queries::Client + Sync, + IO: Io, + >( client: &C, id: u64, current_epoch: Epoch, @@ -664,79 +739,89 @@ pub async fn query_proposal( query_storage_value::(client, &grace_epoch_key) .await?; - println!("Proposal: {}", id); - println!("{:4}Type: {}", "", proposal_type); - println!("{:4}Author: {}", "", author); - println!("{:4}Content:", ""); + display_line!(IO, "Proposal: {}", id); + display_line!(IO, "{:4}Type: {}", "", proposal_type); + display_line!(IO, "{:4}Author: {}", "", author); + display_line!(IO, "{:4}Content:", ""); for (key, value) in &content { - println!("{:8}{}: {}", "", key, value); + display_line!(IO, "{:8}{}: {}", "", key, value); } - println!("{:4}Start Epoch: {}", "", start_epoch); - println!("{:4}End Epoch: {}", "", end_epoch); - println!("{:4}Grace Epoch: {}", "", grace_epoch); - let votes = get_proposal_votes(client, start_epoch, id).await; + display_line!(IO, "{:4}Start Epoch: {}", "", start_epoch); + display_line!(IO, "{:4}End Epoch: {}", "", end_epoch); + display_line!(IO, "{:4}Grace Epoch: {}", "", grace_epoch); + let votes = + get_proposal_votes::<_, IO>(client, start_epoch, id).await; let total_stake = get_total_staked_tokens(client, start_epoch) .await .try_into() .unwrap(); if start_epoch > current_epoch { - println!("{:4}Status: pending", ""); + display_line!(IO, "{:4}Status: pending", ""); } else if start_epoch <= current_epoch && current_epoch <= end_epoch { match utils::compute_tally(votes, total_stake, &proposal_type) { Ok(partial_proposal_result) => { - println!( + display_line!( + IO, "{:4}Yay votes: {}", - "", partial_proposal_result.total_yay_power + "", + partial_proposal_result.total_yay_power ); - println!( + display_line!( + IO, "{:4}Nay votes: {}", - "", partial_proposal_result.total_nay_power + "", + partial_proposal_result.total_nay_power ); - println!("{:4}Status: on-going", ""); + display_line!(IO, "{:4}Status: on-going", ""); } Err(msg) => { - eprintln!("Error in tally computation: {}", msg) + edisplay!(IO, "Error in tally computation: {}", msg); } } } else { match utils::compute_tally(votes, total_stake, &proposal_type) { Ok(proposal_result) => { - println!("{:4}Status: done", ""); - println!("{:4}Result: {}", "", proposal_result); + display_line!(IO, "{:4}Status: done", ""); + display_line!( + IO, + "{:4}Result: {}", + "", + proposal_result + ); } Err(msg) => { - eprintln!("Error in tally computation: {}", msg) + edisplay!(IO, "Error in tally computation: {}", msg); } } } } else { - println!("Proposal: {}", id); - println!("{:4}Type: {}", "", proposal_type); - println!("{:4}Author: {}", "", author); - println!("{:4}Start Epoch: {}", "", start_epoch); - println!("{:4}End Epoch: {}", "", end_epoch); + display_line!(IO, "Proposal: {}", id); + display_line!(IO, "{:4}Type: {}", "", proposal_type); + display_line!(IO, "{:4}Author: {}", "", author); + display_line!(IO, "{:4}Start Epoch: {}", "", start_epoch); + display_line!(IO, "{:4}End Epoch: {}", "", end_epoch); if start_epoch > current_epoch { - println!("{:4}Status: pending", ""); + display_line!(IO, "{:4}Status: pending", ""); } else if start_epoch <= current_epoch && current_epoch <= end_epoch { - println!("{:4}Status: on-going", ""); + display_line!(IO, "{:4}Status: on-going", ""); } else { - println!("{:4}Status: done", ""); + display_line!(IO, "{:4}Status: done", ""); } } Some(()) } - let current_epoch = query_and_print_epoch(client).await; + let current_epoch = query_and_print_epoch::<_, IO>(client).await; match args.proposal_id { Some(id) => { - if print_proposal::(client, id, current_epoch, true) + if print_proposal::(client, id, current_epoch, true) .await .is_none() { - eprintln!("No valid proposal was found with id {}", id) + edisplay!(IO, "No valid proposal was found with id {}", id); } } None => { @@ -747,11 +832,11 @@ pub async fn query_proposal( .unwrap(); for id in 0..last_proposal_id { - if print_proposal::(client, id, current_epoch, false) + if print_proposal::(client, id, current_epoch, false) .await .is_none() { - eprintln!("No valid proposal was found with id {}", id) + edisplay!(IO, "No valid proposal was found with id {}", id); }; } } @@ -762,6 +847,7 @@ pub async fn query_proposal( pub async fn query_shielded_balance< C: namada::ledger::queries::Client + Sync, U: ShieldedUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -788,7 +874,7 @@ pub async fn query_shielded_balance< // Save the update state so that future fetches can be short-circuited let _ = shielded.save().await; // The epoch is required to identify timestamped tokens - let epoch = query_and_print_epoch(client).await; + let epoch = query_and_print_epoch::<_, IO>(client).await; // Map addresses to token names let tokens = wallet.get_addresses_with_vp_type(AddressVpType::Token); match (args.token, owner.is_some()) { @@ -804,7 +890,11 @@ pub async fn query_shielded_balance< .expect("context should contain viewing key") } else { shielded - .compute_exchanged_balance(client, &viewing_key, epoch) + .compute_exchanged_balance::<_, IO>( + client, + &viewing_key, + epoch, + ) .await .expect("context should contain viewing key") }; @@ -821,15 +911,17 @@ pub async fn query_shielded_balance< .cloned() .unwrap_or_default(); if total_balance.is_zero() { - println!( + display_line!( + IO, "No shielded {} balance found for given key", token_address.format_with_alias(&token_alias) ); } else { - println!( + display_line!( + IO, "{}: {}", token_address.format_with_alias(&token_alias), - format_denominated_amount( + format_denominated_amount::<_, IO>( client, &token_address, token::Amount::from(total_balance) @@ -852,7 +944,11 @@ pub async fn query_shielded_balance< .expect("context should contain viewing key") } else { shielded - .compute_exchanged_balance(client, &viewing_key, epoch) + .compute_exchanged_balance::<_, IO>( + client, + &viewing_key, + epoch, + ) .await .expect("context should contain viewing key") }; @@ -876,7 +972,8 @@ pub async fn query_shielded_balance< // remove this from here, should not be making the // hashtable creation any uglier if balances.is_empty() { - println!( + display_line!( + IO, "No shielded {} balance found for any wallet key", &token_addr ); @@ -910,17 +1007,18 @@ pub async fn query_shielded_balance< .get(&token_address.address) .map(|a| a.to_string()) .unwrap_or_else(|| token_address.address.to_string()); - println!( + display_line!( + IO, "Shielded Token {}:", token_address.format_with_alias(&alias), ); - let formatted = format_denominated_amount( + let formatted = format_denominated_amount::<_, IO>( client, &token_address, token_balance.into(), ) .await; - println!(" {}, owned by {}", formatted, fvk); + display_line!(IO, " {}, owned by {}", formatted, fvk); } // Print zero balances for remaining assets for token in tokens { @@ -930,19 +1028,28 @@ pub async fn query_shielded_balance< match sub_addr { // abstract out these prints Some(sub_addr) => { - println!( + display_line!( + IO, "Shielded Token {}/{}:", - token_alias, sub_addr + token_alias, + sub_addr ); - println!( + display_line!( + IO, "No shielded {}/{} balance found for any \ wallet key", - token_alias, sub_addr + token_alias, + sub_addr ); } None => { - println!("Shielded Token {}:", token_alias,); - println!( + display_line!( + IO, + "Shielded Token {}:", + token_alias + ); + display_line!( + IO, "No shielded {} balance found for any \ wallet key", token_alias @@ -966,7 +1073,7 @@ pub async fn query_shielded_balance< ) .unwrap(); let token_alias = lookup_alias(wallet, &token); - println!("Shielded Token {}:", token_alias); + display_line!(IO, "Shielded Token {}:", token_alias); let mut found_any = false; let token_alias = lookup_alias(wallet, &token); let token_address = TokenAddress { @@ -976,7 +1083,8 @@ pub async fn query_shielded_balance< .as_ref() .map(|k| Key::parse(k).unwrap()), }; - println!( + display_line!( + IO, "Shielded Token {}:", token_address.format_with_alias(&token_alias), ); @@ -990,7 +1098,11 @@ pub async fn query_shielded_balance< .expect("context should contain viewing key") } else { shielded - .compute_exchanged_balance(client, &viewing_key, epoch) + .compute_exchanged_balance::<_, IO>( + client, + &viewing_key, + epoch, + ) .await .expect("context should contain viewing key") }; @@ -999,17 +1111,18 @@ pub async fn query_shielded_balance< if !val.is_zero() { found_any = true; } - let formatted = format_denominated_amount( + let formatted = format_denominated_amount::<_, IO>( client, address, (*val).into(), ) .await; - println!(" {}, owned by {}", formatted, fvk); + display_line!(IO, " {}, owned by {}", formatted, fvk); } } if !found_any { - println!( + display_line!( + IO, "No shielded {} balance found for any wallet key", token_address.format_with_alias(&token_alias), ); @@ -1026,14 +1139,22 @@ pub async fn query_shielded_balance< .await .expect("context should contain viewing key"); // Print balances by human-readable token names - print_decoded_balance_with_epoch(client, wallet, balance).await; + print_decoded_balance_with_epoch::<_, IO>( + client, wallet, balance, + ) + .await; } else { let balance = shielded - .compute_exchanged_balance(client, &viewing_key, epoch) + .compute_exchanged_balance::<_, IO>( + client, + &viewing_key, + epoch, + ) .await .expect("context should contain viewing key"); // Print balances by human-readable token names - print_decoded_balance(client, wallet, balance, epoch).await; + print_decoded_balance::<_, IO>(client, wallet, balance, epoch) + .await; } } } @@ -1041,6 +1162,7 @@ pub async fn query_shielded_balance< pub async fn print_decoded_balance< C: namada::ledger::queries::Client + Sync, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -1048,20 +1170,25 @@ pub async fn print_decoded_balance< epoch: Epoch, ) { if decoded_balance.is_empty() { - println!("No shielded balance found for given key"); + display_line!(IO, "No shielded balance found for given key"); } else { for ((_, token_addr), amount) in decoded_balance .iter() .filter(|((token_epoch, _), _)| *token_epoch == epoch) { - println!( + display_line!( + IO, "{} : {}", token_addr.format_with_alias(&lookup_alias( wallet, &token_addr.address )), - format_denominated_amount(client, token_addr, (*amount).into()) - .await, + format_denominated_amount::<_, IO>( + client, + token_addr, + (*amount).into() + ) + .await, ); } } @@ -1069,6 +1196,7 @@ pub async fn print_decoded_balance< pub async fn print_decoded_balance_with_epoch< C: namada::ledger::queries::Client + Sync, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -1076,7 +1204,7 @@ pub async fn print_decoded_balance_with_epoch< ) { let tokens = wallet.get_addresses_with_vp_type(AddressVpType::Token); if decoded_balance.is_empty() { - println!("No shielded balance found for given key"); + display_line!(IO, "No shielded balance found for given key"); } for ((epoch, token_addr), value) in decoded_balance.iter() { let asset_value = (*value).into(); @@ -1084,11 +1212,13 @@ pub async fn print_decoded_balance_with_epoch< .get(&token_addr.address) .map(|a| a.to_string()) .unwrap_or_else(|| token_addr.to_string()); - println!( + display_line!( + IO, "{} | {} : {}", token_addr.format_with_alias(&alias), epoch, - format_denominated_amount(client, token_addr, asset_value).await, + format_denominated_amount::<_, IO>(client, token_addr, asset_value) + .await, ); } } @@ -1104,6 +1234,7 @@ pub async fn get_token_balance( pub async fn query_proposal_result< C: namada::ledger::queries::Client + Sync, + IO: Io, >( client: &C, args: args::QueryProposalResult, @@ -1120,7 +1251,8 @@ pub async fn query_proposal_result< Some(end_epoch) => { if current_epoch > end_epoch { let votes = - get_proposal_votes(client, end_epoch, id).await; + get_proposal_votes::<_, IO>(client, end_epoch, id) + .await; let proposal_type_key = gov_storage::get_proposal_type_key(id); let proposal_type = query_storage_value::< @@ -1136,26 +1268,35 @@ pub async fn query_proposal_result< .await .try_into() .unwrap(); - println!("Proposal: {}", id); + display_line!(IO, "Proposal: {}", id); match utils::compute_tally( votes, total_stake, &proposal_type, ) { Ok(proposal_result) => { - println!("{:4}Result: {}", "", proposal_result) + display_line!( + IO, + "{:4}Result: {}", + "", + proposal_result + ); } Err(msg) => { - eprintln!("Error in tally computation: {}", msg) + edisplay!( + IO, + "Error in tally computation: {}", + msg + ); } } } else { - eprintln!("Proposal is still in progress."); + edisplay!(IO, "Proposal is still in progress."); cli::safe_exit(1) } } None => { - eprintln!("Error while retriving proposal."); + edisplay!(IO, "Error while retriving proposal."); cli::safe_exit(1) } } @@ -1193,7 +1334,8 @@ pub async fn query_proposal_result< } } Err(e) => { - eprintln!( + edisplay!( + IO, "Can't read entry type: {}.", e ); @@ -1201,14 +1343,15 @@ pub async fn query_proposal_result< } }, Err(e) => { - eprintln!("Can't read entry: {}.", e); + edisplay!(IO, "Can't read entry: {}.", e); cli::safe_exit(1) } } } if !is_proposal_present { - eprintln!( + edisplay!( + IO, "The folder must contain the offline proposal \ in a file named \"proposal\"" ); @@ -1228,7 +1371,7 @@ pub async fn query_proposal_result< .expect("Public key should exist."); if !proposal.check_signature(&public_key) { - eprintln!("Bad proposal signature."); + edisplay!(IO, "Bad proposal signature."); cli::safe_exit(1) } @@ -1251,22 +1394,33 @@ pub async fn query_proposal_result< &ProposalType::Default(None), ) { Ok(proposal_result) => { - println!("{:4}Result: {}", "", proposal_result) + display_line!( + IO, + "{:4}Result: {}", + "", + proposal_result + ); } Err(msg) => { - eprintln!("Error in tally computation: {}", msg) + edisplay!( + IO, + "Error in tally computation: {}", + msg + ); } } } None => { - eprintln!( + edisplay!( + IO, "Offline flag must be followed by data-path." ); cli::safe_exit(1) } }; } else { - eprintln!( + edisplay!( + IO, "Either --proposal-id or --data-path should be provided \ as arguments." ); @@ -1278,73 +1432,93 @@ pub async fn query_proposal_result< pub async fn query_protocol_parameters< C: namada::ledger::queries::Client + Sync, + IO: Io, >( client: &C, _args: args::QueryProtocolParameters, ) { let gov_parameters = get_governance_parameters(client).await; - println!("Governance Parameters\n {:4}", gov_parameters); + display_line!(IO, "Governance Parameters\n {:4}", gov_parameters); - println!("Protocol parameters"); + display_line!(IO, "Protocol parameters"); let key = param_storage::get_epoch_duration_storage_key(); let epoch_duration = query_storage_value::(client, &key) .await .expect("Parameter should be definied."); - println!( + display_line!( + IO, "{:4}Min. epoch duration: {}", - "", epoch_duration.min_duration + "", + epoch_duration.min_duration ); - println!( + display_line!( + IO, "{:4}Min. number of blocks: {}", - "", epoch_duration.min_num_of_blocks + "", + epoch_duration.min_num_of_blocks ); let key = param_storage::get_max_expected_time_per_block_key(); let max_block_duration = query_storage_value::(client, &key) .await .expect("Parameter should be defined."); - println!("{:4}Max. block duration: {}", "", max_block_duration); + display_line!(IO, "{:4}Max. block duration: {}", "", max_block_duration); let key = param_storage::get_tx_whitelist_storage_key(); let vp_whitelist = query_storage_value::>(client, &key) .await .expect("Parameter should be defined."); - println!("{:4}VP whitelist: {:?}", "", vp_whitelist); + display_line!(IO, "{:4}VP whitelist: {:?}", "", vp_whitelist); let key = param_storage::get_tx_whitelist_storage_key(); let tx_whitelist = query_storage_value::>(client, &key) .await .expect("Parameter should be defined."); - println!("{:4}Transactions whitelist: {:?}", "", tx_whitelist); + display_line!(IO, "{:4}Transactions whitelist: {:?}", "", tx_whitelist); - println!("PoS parameters"); + display_line!(IO, "PoS parameters"); let key = pos::params_key(); let pos_params = query_storage_value::(client, &key) .await .expect("Parameter should be defined."); - println!( + display_line!( + IO, "{:4}Block proposer reward: {}", - "", pos_params.block_proposer_reward + "", + pos_params.block_proposer_reward ); - println!( + display_line!( + IO, "{:4}Block vote reward: {}", - "", pos_params.block_vote_reward + "", + pos_params.block_vote_reward ); - println!( + display_line!( + IO, "{:4}Duplicate vote minimum slash rate: {}", - "", pos_params.duplicate_vote_min_slash_rate + "", + pos_params.duplicate_vote_min_slash_rate ); - println!( + display_line!( + IO, "{:4}Light client attack minimum slash rate: {}", - "", pos_params.light_client_attack_min_slash_rate + "", + pos_params.light_client_attack_min_slash_rate ); - println!( + display_line!( + IO, "{:4}Max. validator slots: {}", - "", pos_params.max_validator_slots + "", + pos_params.max_validator_slots + ); + display_line!(IO, "{:4}Pipeline length: {}", "", pos_params.pipeline_len); + display_line!(IO, "{:4}Unbonding length: {}", "", pos_params.unbonding_len); + display_line!( + IO, + "{:4}Votes per token: {}", + "", + pos_params.tm_votes_per_token ); - println!("{:4}Pipeline length: {}", "", pos_params.pipeline_len); - println!("{:4}Unbonding length: {}", "", pos_params.unbonding_len); - println!("{:4}Votes per token: {}", "", pos_params.tm_votes_per_token); } pub async fn query_bond( @@ -1375,6 +1549,7 @@ pub async fn query_unbond_with_slashing< pub async fn query_and_print_unbonds< C: namada::ledger::queries::Client + Sync, + IO: Io, >( client: &C, source: &Address, @@ -1395,16 +1570,18 @@ pub async fn query_and_print_unbonds< } } if total_withdrawable != token::Amount::default() { - println!( + display_line!( + IO, "Total withdrawable now: {}.", total_withdrawable.to_string_native() ); } if !not_yet_withdrawable.is_empty() { - println!("Current epoch: {current_epoch}.") + display_line!(IO, "Current epoch: {current_epoch}."); } for (withdraw_epoch, amount) in not_yet_withdrawable { - println!( + display_line!( + IO, "Amount {} withdrawable starting from epoch {withdraw_epoch}.", amount.to_string_native(), ); @@ -1428,12 +1605,12 @@ pub async fn query_withdrawable_tokens< } /// Query PoS bond(s) and unbond(s) -pub async fn query_bonds( +pub async fn query_bonds( client: &C, _wallet: &mut Wallet, args: args::QueryBonds, ) -> std::io::Result<()> { - let epoch = query_and_print_epoch(client).await; + let epoch = query_and_print_epoch::<_, IO>(client).await; let source = args.owner; let validator = args.validator; @@ -1453,24 +1630,26 @@ pub async fn query_bonds( bond_id.source, bond_id.validator ) }; - writeln!(w, "{}:", bond_type)?; + display_line!(IO, &mut w; "{}:", bond_type)?; for bond in &details.data.bonds { - writeln!( - w, + display_line!( + IO, + &mut w; " Remaining active bond from epoch {}: Δ {}", bond.start, bond.amount.to_string_native() )?; } if details.bonds_total != token::Amount::zero() { - writeln!( - w, + display_line!( + IO, + &mut w; "Active (slashed) bonds total: {}", details.bonds_total_active().to_string_native() )?; } - writeln!(w, "Bonds total: {}", details.bonds_total.to_string_native())?; - writeln!(w)?; + display_line!(IO, &mut w; "Bonds total: {}", details.bonds_total.to_string_native())?; + display_line!(IO, &mut w; "")?; if !details.data.unbonds.is_empty() { let bond_type = if bond_id.source == bond_id.validator { @@ -1478,38 +1657,43 @@ pub async fn query_bonds( } else { format!("Unbonded delegations from {}", bond_id.source) }; - writeln!(w, "{}:", bond_type)?; + display_line!(IO, &mut w; "{}:", bond_type)?; for unbond in &details.data.unbonds { - writeln!( - w, + display_line!( + IO, + &mut w; " Withdrawable from epoch {} (active from {}): Δ {}", unbond.withdraw, unbond.start, unbond.amount.to_string_native() )?; } - writeln!( - w, + display_line!( + IO, + &mut w; "Unbonded total: {}", details.unbonds_total.to_string_native() )?; } - writeln!( - w, + display_line!( + IO, + &mut w; "Withdrawable total: {}", details.total_withdrawable.to_string_native() )?; - writeln!(w)?; + display_line!(IO, &mut w; "")?; } if bonds_and_unbonds.bonds_total != bonds_and_unbonds.bonds_total_slashed { - writeln!( - w, + display_line!( + IO, + &mut w; "All bonds total active: {}", bonds_and_unbonds.bonds_total_active().to_string_native() )?; } - writeln!( - w, + display_line!( + IO, + &mut w; "All bonds total: {}", bonds_and_unbonds.bonds_total.to_string_native() )?; @@ -1517,19 +1701,22 @@ pub async fn query_bonds( if bonds_and_unbonds.unbonds_total != bonds_and_unbonds.unbonds_total_slashed { - writeln!( - w, + display_line!( + IO, + &mut w; "All unbonds total active: {}", bonds_and_unbonds.unbonds_total_active().to_string_native() )?; } - writeln!( - w, + display_line!( + IO, + &mut w; "All unbonds total: {}", bonds_and_unbonds.unbonds_total.to_string_native() )?; - writeln!( - w, + display_line!( + IO, + &mut w; "All unbonds total withdrawable: {}", bonds_and_unbonds.total_withdrawable.to_string_native() )?; @@ -1537,13 +1724,16 @@ pub async fn query_bonds( } /// Query PoS bonded stake -pub async fn query_bonded_stake( +pub async fn query_bonded_stake< + C: namada::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, args: args::QueryBondedStake, ) { let epoch = match args.epoch { Some(epoch) => epoch, - None => query_and_print_epoch(client).await, + None => query_and_print_epoch::<_, IO>(client).await, }; match args.validator { @@ -1555,13 +1745,14 @@ pub async fn query_bonded_stake( Some(stake) => { // TODO: show if it's in consensus set, below capacity, or // below threshold set - println!( + display_line!( + IO, "Bonded stake of validator {validator}: {}", stake.to_string_native() ) } None => { - println!("No bonded stake found for {validator}") + display_line!(IO, "No bonded stake found for {validator}"); } } } @@ -1585,21 +1776,24 @@ pub async fn query_bonded_stake( let stdout = io::stdout(); let mut w = stdout.lock(); - writeln!(w, "Consensus validators:").unwrap(); + display_line!(IO, &mut w; "Consensus validators:").unwrap(); for val in consensus { - writeln!( - w, - " {}: {}", - val.address.encode(), - val.bonded_stake.to_string_native() + display_line!( + IO, + &mut w; + " {}: {}", + val.address.encode(), + val.bonded_stake.to_string_native() ) .unwrap(); } if !below_capacity.is_empty() { - writeln!(w, "Below capacity validators:").unwrap(); + display_line!(IO, &mut w; "Below capacity validators:") + .unwrap(); for val in &below_capacity { - writeln!( - w, + display_line!( + IO, + &mut w; " {}: {}", val.address.encode(), val.bonded_stake.to_string_native() @@ -1611,7 +1805,8 @@ pub async fn query_bonded_stake( } let total_staked_tokens = get_total_staked_tokens(client, epoch).await; - println!( + display_line!( + IO, "Total bonded stake: {}", total_staked_tokens.to_string_native() ); @@ -1637,6 +1832,7 @@ pub async fn query_commission_rate< /// Query PoS validator's commission rate information pub async fn query_and_print_commission_rate< C: namada::ledger::queries::Client + Sync, + IO: Io, >( client: &C, _wallet: &mut Wallet, @@ -1651,7 +1847,8 @@ pub async fn query_and_print_commission_rate< commission_rate: rate, max_commission_change_per_epoch: change, }) => { - println!( + display_line!( + IO, "Validator {} commission rate: {}, max change per epoch: {}", validator.encode(), rate, @@ -1659,7 +1856,8 @@ pub async fn query_and_print_commission_rate< ); } None => { - println!( + display_line!( + IO, "Address {} is not a validator (did not find commission rate \ and max change)", validator.encode(), @@ -1669,7 +1867,10 @@ pub async fn query_and_print_commission_rate< } /// Query PoS slashes -pub async fn query_slashes( +pub async fn query_slashes< + C: namada::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, _wallet: &mut Wallet, args: args::QuerySlashes, @@ -1690,15 +1891,16 @@ pub async fn query_slashes( let stdout = io::stdout(); let mut w = stdout.lock(); for slash in slashes { - writeln!( - w, - "Slash epoch {}, type {}, rate {}", - slash.epoch, slash.r#type, slash.rate + display_line!( + IO, + &mut w; + "Slash epoch {}, type {}, rate {}", + slash.epoch, slash.r#type, slash.rate ) .unwrap(); } } else { - println!("No slashes found for {}", validator.encode()) + display_line!(IO, "No slashes found for {}", validator.encode()) } } None => { @@ -1712,8 +1914,9 @@ pub async fn query_slashes( let mut w = stdout.lock(); for (validator, slashes) in all_slashes.into_iter() { for slash in slashes { - writeln!( - w, + display_line!( + IO, + &mut w; "Slash epoch {}, block height {}, rate {}, type \ {}, validator {}", slash.epoch, @@ -1726,13 +1929,16 @@ pub async fn query_slashes( } } } else { - println!("No slashes found") + display_line!(IO, "No slashes found") } } } } -pub async fn query_delegations( +pub async fn query_delegations< + C: namada::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, _wallet: &mut Wallet, args: args::QueryDelegations, @@ -1742,22 +1948,26 @@ pub async fn query_delegations( RPC.vp().pos().delegation_validators(client, &owner).await, ); if delegations.is_empty() { - println!("No delegations found"); + display_line!(IO, "No delegations found"); } else { - println!("Found delegations to:"); + display_line!(IO, "Found delegations to:"); for delegation in delegations { - println!(" {delegation}"); + display_line!(IO, " {delegation}"); } } } -pub async fn query_find_validator( +pub async fn query_find_validator< + C: namada::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, args: args::QueryFindValidator, ) { let args::QueryFindValidator { query: _, tm_addr } = args; if tm_addr.len() != 40 { - eprintln!( + edisplay!( + IO, "Expected 40 characters in Tendermint address, got {}", tm_addr.len() ); @@ -1768,22 +1978,28 @@ pub async fn query_find_validator( RPC.vp().pos().validator_by_tm_addr(client, &tm_addr).await, ); match validator { - Some(address) => println!("Found validator address \"{address}\"."), + Some(address) => { + display_line!(IO, "Found validator address \"{address}\".") + } None => { - println!("No validator with Tendermint address {tm_addr} found.") + display_line!( + IO, + "No validator with Tendermint address {tm_addr} found." + ) } } } /// Dry run a transaction -pub async fn dry_run_tx(client: &C, tx_bytes: Vec) +pub async fn dry_run_tx(client: &C, tx_bytes: Vec) where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - println!( + display_line!( + IO, "Dry-run result: {}", - namada::ledger::rpc::dry_run_tx(client, tx_bytes).await + namada::ledger::rpc::dry_run_tx::<_, IO>(client, tx_bytes).await ); } @@ -1830,7 +2046,10 @@ pub async fn known_address( } /// Query for all conversions. -pub async fn query_conversions( +pub async fn query_conversions< + C: namada::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, wallet: &mut Wallet, args: args::QueryConversions, @@ -1863,7 +2082,8 @@ pub async fn query_conversions( } conversions_found = true; // Print the asset to which the conversion applies - print!( + display!( + IO, "{}{}[{}]: ", tokens.get(addr).cloned().unwrap_or_else(|| addr.clone()), sub.as_ref().map(|k| format!("/{}", k)).unwrap_or_default(), @@ -1876,7 +2096,8 @@ pub async fn query_conversions( // printing let ((addr, sub, _), epoch, _, _) = &conv_state.assets[asset_type]; // Now print out this component of the conversion - print!( + display!( + IO, "{}{} {}{}[{}]", prefix, val, @@ -1888,10 +2109,13 @@ pub async fn query_conversions( prefix = " + "; } // Allowed conversions are always implicit equations - println!(" = 0"); + display_line!(IO, " = 0"); } if !conversions_found { - println!("No conversions found satisfying specified criteria."); + display_line!( + IO, + "No conversions found satisfying specified criteria." + ); } } @@ -1911,11 +2135,14 @@ pub async fn query_conversion( } /// Query a wasm code hash -pub async fn query_wasm_code_hash( +pub async fn query_wasm_code_hash< + C: namada::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, code_path: impl AsRef, ) -> Option { - namada::ledger::rpc::query_wasm_code_hash(client, code_path).await + namada::ledger::rpc::query_wasm_code_hash::<_, IO>(client, code_path).await } /// Query a storage value and decode it with [`BorshDeserialize`]. @@ -1948,6 +2175,7 @@ pub async fn query_storage_value_bytes< pub async fn query_storage_prefix< C: namada::ledger::queries::Client + Sync, T, + IO: Io, >( client: &C, key: &storage::Key, @@ -1955,7 +2183,7 @@ pub async fn query_storage_prefix< where T: BorshDeserialize, { - namada::ledger::rpc::query_storage_prefix(client, key).await + namada::ledger::rpc::query_storage_prefix::<_, IO, _>(client, key).await } /// Query to check if the given storage key exists. @@ -1991,7 +2219,7 @@ pub async fn query_tx_response( /// Lookup the results of applying the specified transaction to the /// blockchain. -pub async fn query_result( +pub async fn query_result( client: &C, args: args::QueryResult, ) { @@ -2003,7 +2231,8 @@ pub async fn query_result( .await; match tx_response { Ok(result) => { - println!( + display_line!( + IO, "Transaction was applied with result: {}", serde_json::to_string_pretty(&result).unwrap() ) @@ -2016,13 +2245,14 @@ pub async fn query_result( ) .await; match tx_response { - Ok(result) => println!( + Ok(result) => display_line!( + IO, "Transaction was accepted with result: {}", serde_json::to_string_pretty(&result).unwrap() ), Err(err2) => { // Print the errors that caused the lookups to fail - eprintln!("{}\n{}", err1, err2); + edisplay!(IO, "{}\n{}", err1, err2); cli::safe_exit(1) } } @@ -2030,12 +2260,16 @@ pub async fn query_result( } } -pub async fn get_proposal_votes( +pub async fn get_proposal_votes< + C: namada::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, epoch: Epoch, proposal_id: u64, ) -> Votes { - namada::ledger::rpc::get_proposal_votes(client, epoch, proposal_id).await + namada::ledger::rpc::get_proposal_votes::<_, IO>(client, epoch, proposal_id) + .await } pub async fn get_proposal_offline_votes< @@ -2309,7 +2543,10 @@ fn unwrap_client_response( } /// Get the correct representation of the amount given the token type. -pub async fn validate_amount( +pub async fn validate_amount< + C: namada::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, amount: InputAmount, token: &Address, @@ -2328,13 +2565,15 @@ pub async fn validate_amount( ) .unwrap_or_else(|| { if force { - println!( + display_line!( + IO, "No denomination found for token: {token}, but --force was \ passed. Defaulting to the provided denomination." ); input_amount.denom } else { - println!( + display_line!( + IO, "No denomination found for token: {token}, the input \ arguments could not be parsed." ); @@ -2342,14 +2581,16 @@ pub async fn validate_amount( } }); if denom < input_amount.denom && !force { - println!( + display_line!( + IO, "The input amount contained a higher precision than allowed by \ {token}." ); cli::safe_exit(1); } else { input_amount.increase_precision(denom).unwrap_or_else(|_| { - println!( + display_line!( + IO, "The amount provided requires more the 256 bits to represent." ); cli::safe_exit(1); diff --git a/apps/src/lib/client/signing.rs b/apps/src/lib/client/signing.rs index 3c2a5d67fe..34ee2bcc29 100644 --- a/apps/src/lib/client/signing.rs +++ b/apps/src/lib/client/signing.rs @@ -8,13 +8,14 @@ use namada::ledger::wallet::{Wallet, WalletUtils}; use namada::proof_of_stake::Epoch; use namada::proto::Tx; use namada::types::address::Address; +use namada::types::io::Io; use namada::types::key::*; use crate::cli::args; /// Find the public key for the given address and try to load the keypair /// for it from the wallet. Panics if the key cannot be found or loaded. -pub async fn find_pk( +pub async fn find_pk( client: &C, wallet: &mut Wallet, addr: &Address, @@ -24,14 +25,15 @@ where C::Error: std::fmt::Display, U: WalletUtils, { - namada::ledger::signing::find_pk(client, wallet, addr, None).await + namada::ledger::signing::find_pk::<_, _, IO>(client, wallet, addr, None) + .await } /// Given CLI arguments and some defaults, determine the rightful transaction /// 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_signer( client: &C, wallet: &mut Wallet, args: &args::Tx, @@ -42,8 +44,10 @@ where C::Error: std::fmt::Display, U: WalletUtils, { - namada::ledger::signing::tx_signer::(client, wallet, args, default) - .await + namada::ledger::signing::tx_signer::( + client, wallet, args, default, + ) + .await } /// Sign a transaction with a given signing key or public key of a given signer. @@ -71,7 +75,7 @@ where /// 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 sign_wrapper( +pub async fn sign_wrapper( client: &C, wallet: &mut Wallet, args: &args::Tx, @@ -85,7 +89,7 @@ where C::Error: std::fmt::Display, U: WalletUtils, { - namada::ledger::signing::sign_wrapper( + namada::ledger::signing::sign_wrapper::<_, _, IO>( client, wallet, args, diff --git a/apps/src/lib/client/tx.rs b/apps/src/lib/client/tx.rs index e2683babba..75067088a8 100644 --- a/apps/src/lib/client/tx.rs +++ b/apps/src/lib/client/tx.rs @@ -22,11 +22,13 @@ use namada::types::dec::Dec; use namada::types::governance::{ OfflineProposal, OfflineVote, Proposal, ProposalVote, VoteType, }; +use namada::types::io::Io; use namada::types::key::{self, *}; use namada::types::storage::{Epoch, Key}; use namada::types::token; use namada::types::transaction::governance::{ProposalType, VoteProposalData}; use namada::types::transaction::{InitValidator, TxType}; +use namada::{display_line, edisplay}; use super::rpc; use crate::cli::context::WalletAddress; @@ -40,7 +42,10 @@ use crate::node::ledger::tendermint_node; use crate::wallet::{gen_validator_keys, read_and_confirm_encryption_password}; // Build a transaction to reveal the signer of the given transaction. -pub async fn submit_reveal_aux( +pub async fn submit_reveal_aux< + C: namada::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, ctx: &mut Context, args: &args::Tx, @@ -49,7 +54,7 @@ pub async fn submit_reveal_aux( tx: &mut Tx, ) -> Result<(), tx::Error> { if let Some(Address::Implicit(_)) = addr { - let reveal_pk = tx::build_reveal_pk( + let reveal_pk = tx::build_reveal_pk::<_, _, IO>( client, &mut ctx.wallet, args::RevealPk { @@ -62,16 +67,20 @@ pub async fn submit_reveal_aux( // Sign the reveal public key transaction with the fee payer signing::sign_tx(&mut ctx.wallet, &mut rtx, args, &pk).await?; // Submit the reveal public key transaction first - tx::process_tx(client, &mut ctx.wallet, args, rtx).await?; + tx::process_tx::<_, _, IO>(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, &pk, false).await; + signing::update_pow_challenge::<_, IO>( + client, args, tx, &pk, false, + ) + .await; } } Ok(()) } -pub async fn submit_custom( +pub async fn submit_custom( client: &C, ctx: &mut Context, args: args::TxCustom, @@ -81,14 +90,23 @@ where C::Error: std::fmt::Display, { let (mut tx, addr, pk) = - tx::build_custom(client, &mut ctx.wallet, args.clone()).await?; - submit_reveal_aux(client, ctx, &args.tx, addr, pk.clone(), &mut tx).await?; + tx::build_custom::<_, _, IO>(client, &mut ctx.wallet, args.clone()) + .await?; + submit_reveal_aux::<_, IO>( + client, + ctx, + &args.tx, + addr, + pk.clone(), + &mut tx, + ) + .await?; signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx).await?; Ok(()) } -pub async fn submit_update_vp( +pub async fn submit_update_vp( client: &C, ctx: &mut Context, args: args::TxUpdateVp, @@ -98,14 +116,23 @@ where C::Error: std::fmt::Display, { let (mut tx, addr, pk) = - tx::build_update_vp(client, &mut ctx.wallet, args.clone()).await?; - submit_reveal_aux(client, ctx, &args.tx, addr, pk.clone(), &mut tx).await?; + tx::build_update_vp::<_, _, IO>(client, &mut ctx.wallet, args.clone()) + .await?; + submit_reveal_aux::<_, IO>( + client, + ctx, + &args.tx, + addr, + pk.clone(), + &mut tx, + ) + .await?; signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx).await?; Ok(()) } -pub async fn submit_init_account( +pub async fn submit_init_account( client: &C, ctx: &mut Context, args: args::TxInitAccount, @@ -114,15 +141,27 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, pk) = - tx::build_init_account(client, &mut ctx.wallet, args.clone()).await?; - submit_reveal_aux(client, ctx, &args.tx, addr, pk.clone(), &mut tx).await?; + let (mut tx, addr, pk) = tx::build_init_account::<_, _, IO>( + client, + &mut ctx.wallet, + args.clone(), + ) + .await?; + submit_reveal_aux::<_, IO>( + client, + ctx, + &args.tx, + addr, + pk.clone(), + &mut tx, + ) + .await?; signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx).await?; Ok(()) } -pub async fn submit_init_validator( +pub async fn submit_init_validator( client: &C, mut ctx: Context, args::TxInitValidator { @@ -163,7 +202,7 @@ where let eth_hot_key_alias = format!("{}-eth-hot-key", alias); let eth_cold_key_alias = format!("{}-eth-cold-key", alias); let account_key = account_key.unwrap_or_else(|| { - println!("Generating validator account key..."); + display_line!(IO, "Generating validator account key..."); let password = read_and_confirm_encryption_password(unsafe_dont_encrypt); ctx.wallet @@ -184,12 +223,12 @@ where .map(|key| match key { common::SecretKey::Ed25519(_) => key, common::SecretKey::Secp256k1(_) => { - eprintln!("Consensus key can only be ed25519"); + edisplay!(IO, "Consensus key can only be ed25519"); safe_exit(1) } }) .unwrap_or_else(|| { - println!("Generating consensus key..."); + display_line!(IO, "Generating consensus key..."); let password = read_and_confirm_encryption_password(unsafe_dont_encrypt); ctx.wallet @@ -210,12 +249,12 @@ where .map(|key| match key { common::SecretKey::Secp256k1(_) => key.ref_to(), common::SecretKey::Ed25519(_) => { - eprintln!("Eth cold key can only be secp256k1"); + edisplay!(IO, "Eth cold key can only be secp256k1"); safe_exit(1) } }) .unwrap_or_else(|| { - println!("Generating Eth cold key..."); + display_line!(IO, "Generating Eth cold key..."); let password = read_and_confirm_encryption_password(unsafe_dont_encrypt); ctx.wallet @@ -237,12 +276,12 @@ where .map(|key| match key { common::SecretKey::Secp256k1(_) => key.ref_to(), common::SecretKey::Ed25519(_) => { - eprintln!("Eth hot key can only be secp256k1"); + edisplay!(IO, "Eth hot key can only be secp256k1"); safe_exit(1) } }) .unwrap_or_else(|| { - println!("Generating Eth hot key..."); + display_line!(IO, "Generating Eth hot key..."); let password = read_and_confirm_encryption_password(unsafe_dont_encrypt); ctx.wallet @@ -261,7 +300,7 @@ where }); if protocol_key.is_none() { - println!("Generating protocol signing key..."); + display_line!(IO, "Generating protocol signing key..."); } // Generate the validator keys let validator_keys = gen_validator_keys( @@ -278,7 +317,7 @@ where .expect("DKG sessions keys should have been created") .public(); - let validator_vp_code_hash = query_wasm_code_hash::( + let validator_vp_code_hash = query_wasm_code_hash::( client, validator_vp_code_path.to_str().unwrap(), ) @@ -287,7 +326,8 @@ where // Validate the commission rate data if commission_rate > Dec::one() || commission_rate < Dec::zero() { - eprintln!( + edisplay!( + IO, "The validator commission rate must not exceed 1.0 or 100%, and \ it must be 0 or positive" ); @@ -298,7 +338,8 @@ where if max_commission_rate_change > Dec::one() || max_commission_rate_change < Dec::zero() { - eprintln!( + edisplay!( + IO, "The validator maximum change in commission rate per epoch must \ not exceed 1.0 or 100%" ); @@ -307,7 +348,7 @@ where } } let tx_code_hash = - query_wasm_code_hash(client, args::TX_INIT_VALIDATOR_WASM) + query_wasm_code_hash::<_, IO>(client, args::TX_INIT_VALIDATOR_WASM) .await .unwrap(); @@ -334,7 +375,7 @@ where tx.set_data(Data::new(data)); tx.set_code(Code::from_hash(tx_code_hash)); - let (mut tx, addr, pk) = tx::prepare_tx( + let (mut tx, addr, pk) = tx::prepare_tx::<_, _, IO>( client, &mut ctx.wallet, &tx_args, @@ -344,12 +385,20 @@ where false, ) .await?; - submit_reveal_aux(client, &mut ctx, &tx_args, addr, pk.clone(), &mut tx) - .await?; + submit_reveal_aux::<_, IO>( + client, + &mut ctx, + &tx_args, + addr, + pk.clone(), + &mut tx, + ) + .await?; signing::sign_tx(&mut ctx.wallet, &mut tx, &tx_args, &pk).await?; - let result = tx::process_tx(client, &mut ctx.wallet, &tx_args, tx) - .await? - .initialized_accounts(); + let result = + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &tx_args, tx) + .await? + .initialized_accounts(); if !tx_args.dry_run { let (validator_address_alias, validator_address) = match &result[..] { @@ -358,12 +407,12 @@ where if let Some(alias) = ctx.wallet.find_alias(validator_address) { (alias.clone(), validator_address.clone()) } else { - eprintln!("Expected one account to be created"); + edisplay!(IO, "Expected one account to be created"); safe_exit(1) } } _ => { - eprintln!("Expected one account to be created"); + edisplay!(IO, "Expected one account to be created"); safe_exit(1) } }; @@ -371,7 +420,7 @@ where ctx.wallet .add_validator_data(validator_address, validator_keys); crate::wallet::save(&ctx.wallet) - .unwrap_or_else(|err| eprintln!("{}", err)); + .unwrap_or_else(|err| edisplay!(IO, "{}", err)); let tendermint_home = ctx.config.ledger.cometbft_dir(); tendermint_node::write_validator_key(&tendermint_home, &consensus_key); @@ -393,24 +442,35 @@ where .await .expect("Pos parameter should be defined."); - println!(); - println!( + display_line!(IO, ""); + display_line!( + IO, "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!( + display_line!( + IO, + " Validator address \"{}\"", + validator_address_alias + ); + display_line!( + IO, + " Validator account key \"{}\"", + validator_key_alias + ); + display_line!(IO, " Consensus key \"{}\"", consensus_key_alias); + display_line!( + IO, "The ledger node has been setup to use this validator's address \ and consensus key." ); - println!( + display_line!( + IO, "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."); + display_line!(IO, "Transaction dry run. No addresses have been saved."); } Ok(()) } @@ -428,7 +488,7 @@ pub struct CLIShieldedUtils { impl CLIShieldedUtils { /// Initialize a shielded transaction context that identifies notes /// decryptable by any viewing key in the given set - pub fn new(context_dir: PathBuf) -> masp::ShieldedContext { + pub fn new(context_dir: PathBuf) -> masp::ShieldedContext { // Make sure that MASP parameters are downloaded to enable MASP // transaction building and verification later on let params_dir = masp::get_params_dir(); @@ -439,10 +499,13 @@ impl CLIShieldedUtils { && convert_path.exists() && output_path.exists()) { - println!("MASP parameters not present, downloading..."); + display_line!(IO, "MASP parameters not present, downloading..."); masp_proofs::download_masp_parameters(None) .expect("MASP parameters not present or downloadable"); - println!("MASP parameter download complete, resuming execution..."); + display_line!( + IO, + "MASP parameter download complete, resuming execution..." + ); } // Finally initialize a shielded context with the supplied directory let utils = Self { context_dir }; @@ -523,7 +586,7 @@ impl masp::ShieldedUtils for CLIShieldedUtils { } } -pub async fn submit_transfer( +pub async fn submit_transfer( client: &C, mut ctx: Context, args: args::TxTransfer, @@ -531,9 +594,14 @@ pub async fn submit_transfer( for _ in 0..2 { let arg = args.clone(); let (mut tx, addr, pk, tx_epoch, _isf) = - tx::build_transfer(client, &mut ctx.wallet, &mut ctx.shielded, arg) - .await?; - submit_reveal_aux( + tx::build_transfer::<_, _, _, IO>( + client, + &mut ctx.wallet, + &mut ctx.shielded, + arg, + ) + .await?; + submit_reveal_aux::<_, IO>( client, &mut ctx, &args.tx, @@ -544,9 +612,11 @@ pub async fn submit_transfer( .await?; signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; let result = - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + tx::process_tx::<_, _, IO>(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; + let submission_epoch = + rpc::query_and_print_epoch::<_, IO>(client).await; match result { ProcessTxResponse::Applied(resp) if @@ -558,7 +628,7 @@ pub async fn submit_transfer( tx_epoch.unwrap() != submission_epoch => { // Then we probably straddled an epoch boundary. Let's retry... - eprintln!( + edisplay!(IO, "MASP transaction rejected and this may be due to the \ epoch changing. Attempting to resubmit transaction.", ); @@ -572,7 +642,7 @@ pub async fn submit_transfer( Ok(()) } -pub async fn submit_ibc_transfer( +pub async fn submit_ibc_transfer( client: &C, mut ctx: Context, args: args::TxIbcTransfer, @@ -581,16 +651,27 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, pk) = - tx::build_ibc_transfer(client, &mut ctx.wallet, args.clone()).await?; - submit_reveal_aux(client, &mut ctx, &args.tx, addr, pk.clone(), &mut tx) - .await?; + let (mut tx, addr, pk) = tx::build_ibc_transfer::<_, _, IO>( + client, + &mut ctx.wallet, + args.clone(), + ) + .await?; + submit_reveal_aux::<_, IO>( + client, + &mut ctx, + &args.tx, + addr, + pk.clone(), + &mut tx, + ) + .await?; signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx).await?; Ok(()) } -pub async fn submit_init_proposal( +pub async fn submit_init_proposal( client: &C, mut ctx: Context, args: args::InitProposal, @@ -604,7 +685,7 @@ where serde_json::from_reader(file).expect("JSON was not well-formatted"); let signer = WalletAddress::new(proposal.clone().author.to_string()); - let current_epoch = rpc::query_and_print_epoch(client).await; + let current_epoch = rpc::query_and_print_epoch::<_, IO>(client).await; let governance_parameters = rpc::get_governance_parameters(client).await; if proposal.voting_start_epoch <= current_epoch @@ -612,14 +693,16 @@ where % governance_parameters.min_proposal_period != 0 { - println!("{}", proposal.voting_start_epoch <= current_epoch); - println!( + display_line!(IO, "{}", proposal.voting_start_epoch <= current_epoch); + display_line!( + IO, "{}", proposal.voting_start_epoch.0 % governance_parameters.min_proposal_period == 0 ); - eprintln!( + edisplay!( + IO, "Invalid proposal start epoch: {} must be greater than current \ epoch {} and a multiple of {}", proposal.voting_start_epoch, @@ -636,7 +719,8 @@ where > governance_parameters.max_proposal_period || proposal.voting_end_epoch.0 % 3 != 0 { - eprintln!( + edisplay!( + IO, "Invalid proposal end epoch: difference between proposal start \ and end epoch must be at least {} and at max {} and end epoch \ must be a multiple of {}", @@ -651,7 +735,8 @@ where || proposal.grace_epoch.0 - proposal.voting_end_epoch.0 < governance_parameters.min_proposal_grace_epochs { - eprintln!( + edisplay!( + IO, "Invalid proposal grace epoch: difference between proposal grace \ and end epoch must be at least {}", governance_parameters.min_proposal_grace_epochs @@ -663,7 +748,7 @@ where if args.offline { let signer = ctx.get(&signer); - let key = find_pk(client, &mut ctx.wallet, &signer).await?; + let key = find_pk::<_, _, IO>(client, &mut ctx.wallet, &signer).await?; let signing_key = signing::find_key_by_pk(&mut ctx.wallet, &args.tx, &key)?; let offline_proposal = @@ -676,13 +761,14 @@ where let out = File::create(&proposal_filename).unwrap(); match serde_json::to_writer_pretty(out, &offline_proposal) { Ok(_) => { - println!( + display_line!( + IO, "Proposal created: {}.", proposal_filename.to_string_lossy() ); } Err(e) => { - eprintln!("Error while creating proposal file: {}.", e); + edisplay!(IO, "Error while creating proposal file: {}.", e); safe_exit(1) } } @@ -694,7 +780,7 @@ where if let Ok(data) = tx_data { data } else { - eprintln!("Invalid data for init proposal transaction."); + edisplay!(IO, "Invalid data for init proposal transaction."); safe_exit(1) }; @@ -709,7 +795,8 @@ where ) .unwrap() { - eprintln!( + edisplay!( + IO, "Address {} doesn't have enough funds.", &proposal.author ); @@ -719,14 +806,15 @@ where if init_proposal_content.len() > governance_parameters.max_proposal_content_size as usize { - eprintln!("Proposal content size too big.",); + edisplay!(IO, "Proposal content size too big."); 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(); + let tx_code_hash = + query_wasm_code_hash::<_, IO>(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 @@ -751,7 +839,7 @@ where tx.set_data(Data::new(data)); tx.set_code(Code::from_hash(tx_code_hash)); - let (mut tx, addr, pk) = tx::prepare_tx( + let (mut tx, addr, pk) = tx::prepare_tx::<_, _, IO>( client, &mut ctx.wallet, &args.tx, @@ -761,7 +849,7 @@ where false, ) .await?; - submit_reveal_aux( + submit_reveal_aux::<_, IO>( client, &mut ctx, &args.tx, @@ -771,12 +859,13 @@ where ) .await?; signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx) + .await?; Ok(()) } } -pub async fn submit_vote_proposal( +pub async fn submit_vote_proposal( client: &C, mut ctx: Context, args: args::VoteProposal, @@ -788,7 +877,7 @@ where let signer = if let Some(addr) = &args.tx.signer { addr } else { - eprintln!("Missing mandatory argument --signer."); + edisplay!(IO, "Missing mandatory argument --signer."); safe_exit(1) }; @@ -828,7 +917,7 @@ where let msg = splits.next().expect("Missing message to sign"); if splits.next().is_some() { - eprintln!("Unexpected argument after message"); + edisplay!(IO, "Unexpected argument after message"); safe_exit(1); } @@ -844,14 +933,15 @@ where } "nay" => ProposalVote::Nay, _ => { - eprintln!("Vote must be either yay or nay"); + edisplay!(IO, "Vote must be either yay or nay"); safe_exit(1); } }; if args.offline { if !proposal_vote.is_default_vote() { - eprintln!( + edisplay!( + IO, "Wrong vote type for offline proposal. Just vote yay or nay!" ); safe_exit(1); @@ -866,11 +956,11 @@ where .await .expect("Public key should exist."); if !proposal.check_signature(&public_key) { - eprintln!("Proposal signature mismatch!"); + edisplay!(IO, "Proposal signature mismatch!"); safe_exit(1) } - let key = find_pk(client, &mut ctx.wallet, signer).await?; + let key = find_pk::<_, _, IO>(client, &mut ctx.wallet, signer).await?; let signing_key = signing::find_key_by_pk(&mut ctx.wallet, &args.tx, &key)?; let offline_vote = OfflineVote::new( @@ -887,19 +977,24 @@ where let out = File::create(&proposal_vote_filename).unwrap(); match serde_json::to_writer_pretty(out, &offline_vote) { Ok(_) => { - println!( + display_line!( + IO, "Proposal vote created: {}.", proposal_vote_filename.to_string_lossy() ); Ok(()) } Err(e) => { - eprintln!("Error while creating proposal vote file: {}.", e); + edisplay!( + IO, + "Error while creating proposal vote file: {}.", + e + ); safe_exit(1) } } } else { - let current_epoch = rpc::query_and_print_epoch(client).await; + let current_epoch = rpc::query_and_print_epoch::<_, IO>(client).await; let voter_address = signer.clone(); let proposal_id = args.proposal_id.unwrap(); @@ -924,9 +1019,11 @@ where if let ProposalVote::Yay(ref vote_type) = proposal_vote { if &proposal_type != vote_type { - eprintln!( + edisplay!( + IO, "Expected vote of type {}, found {}", - proposal_type, args.vote + proposal_type, + args.vote ); safe_exit(1); } else if let VoteType::PGFCouncil(set) = vote_type { @@ -939,7 +1036,8 @@ where if !rpc::query_has_storage_key::(client, &vp_key) .await { - eprintln!( + edisplay!( + IO, "Proposed PGF council {} cannot be found \ in storage", address @@ -948,7 +1046,8 @@ where } } _ => { - eprintln!( + edisplay!( + IO, "PGF council vote contains a non-established \ address: {}", address @@ -963,10 +1062,12 @@ where match proposal_start_epoch { Some(epoch) => { if current_epoch < epoch { - eprintln!( + edisplay!( + IO, "Current epoch {} is not greater than proposal start \ epoch {}", - current_epoch, epoch + current_epoch, + epoch ); if !args.tx.force { @@ -1008,7 +1109,7 @@ where .try_to_vec() .expect("Encoding proposal data shouldn't fail"); - let tx_code_hash = query_wasm_code_hash( + let tx_code_hash = query_wasm_code_hash::<_, IO>( client, args.tx_code_path.to_str().unwrap(), ) @@ -1020,7 +1121,7 @@ where tx.set_data(Data::new(data)); tx.set_code(Code::from_hash(tx_code_hash)); - let (mut tx, addr, pk) = tx::prepare_tx( + let (mut tx, addr, pk) = tx::prepare_tx::<_, _, IO>( client, &mut ctx.wallet, &args.tx, @@ -1030,7 +1131,7 @@ where false, ) .await?; - submit_reveal_aux( + submit_reveal_aux::<_, IO>( client, &mut ctx, &args.tx, @@ -1041,11 +1142,18 @@ where .await?; signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk) .await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + tx::process_tx::<_, _, IO>( + client, + &mut ctx.wallet, + &args.tx, + tx, + ) + .await?; Ok(()) } None => { - eprintln!( + edisplay!( + IO, "Proposal start epoch for proposal id {} is not definied.", proposal_id ); @@ -1055,7 +1163,7 @@ where } } -pub async fn submit_reveal_pk( +pub async fn submit_reveal_pk( client: &C, ctx: &mut Context, args: args::RevealPk, @@ -1065,10 +1173,12 @@ where C::Error: std::fmt::Display, { let reveal_tx = - tx::build_reveal_pk(client, &mut ctx.wallet, args.clone()).await?; + tx::build_reveal_pk::<_, _, IO>(client, &mut ctx.wallet, args.clone()) + .await?; if let Some((mut tx, _, pk)) = reveal_tx { signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx) + .await?; } Ok(()) } @@ -1131,7 +1241,7 @@ where delegations.into_iter().flatten().collect() } -pub async fn submit_bond( +pub async fn submit_bond( client: &C, ctx: &mut Context, args: args::Bond, @@ -1141,14 +1251,23 @@ where C::Error: std::fmt::Display, { let (mut tx, addr, pk) = - tx::build_bond::(client, &mut ctx.wallet, args.clone()).await?; - submit_reveal_aux(client, ctx, &args.tx, addr, pk.clone(), &mut tx).await?; + tx::build_bond::(client, &mut ctx.wallet, args.clone()) + .await?; + submit_reveal_aux::<_, IO>( + client, + ctx, + &args.tx, + addr, + pk.clone(), + &mut tx, + ) + .await?; signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx).await?; Ok(()) } -pub async fn submit_unbond( +pub async fn submit_unbond( client: &C, ctx: &mut Context, args: args::Unbond, @@ -1158,15 +1277,25 @@ where C::Error: std::fmt::Display, { let (mut tx, addr, pk, latest_withdrawal_pre) = - tx::build_unbond(client, &mut ctx.wallet, args.clone()).await?; - submit_reveal_aux(client, ctx, &args.tx, addr, pk.clone(), &mut tx).await?; + tx::build_unbond::<_, _, IO>(client, &mut ctx.wallet, args.clone()) + .await?; + submit_reveal_aux::<_, IO>( + client, + ctx, + &args.tx, + addr, + pk.clone(), + &mut tx, + ) + .await?; signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; - tx::query_unbonds(client, args.clone(), latest_withdrawal_pre).await?; + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx).await?; + tx::query_unbonds::<_, IO>(client, args.clone(), latest_withdrawal_pre) + .await?; Ok(()) } -pub async fn submit_withdraw( +pub async fn submit_withdraw( client: &C, mut ctx: Context, args: args::Withdraw, @@ -1176,15 +1305,23 @@ where C::Error: std::fmt::Display, { let (mut tx, addr, pk) = - tx::build_withdraw(client, &mut ctx.wallet, args.clone()).await?; - submit_reveal_aux(client, &mut ctx, &args.tx, addr, pk.clone(), &mut tx) - .await?; + tx::build_withdraw::<_, _, IO>(client, &mut ctx.wallet, args.clone()) + .await?; + submit_reveal_aux::<_, IO>( + client, + &mut ctx, + &args.tx, + addr, + pk.clone(), + &mut tx, + ) + .await?; signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx).await?; Ok(()) } -pub async fn submit_validator_commission_change( +pub async fn submit_validator_commission_change( client: &C, mut ctx: Context, args: args::CommissionRateChange, @@ -1194,18 +1331,29 @@ where C::Error: std::fmt::Display, { let arg = args.clone(); - let (mut tx, addr, pk) = - tx::build_validator_commission_change(client, &mut ctx.wallet, arg) - .await?; - submit_reveal_aux(client, &mut ctx, &args.tx, addr, pk.clone(), &mut tx) - .await?; + let (mut tx, addr, pk) = tx::build_validator_commission_change::<_, _, IO>( + client, + &mut ctx.wallet, + arg, + ) + .await?; + submit_reveal_aux::<_, IO>( + client, + &mut ctx, + &args.tx, + addr, + pk.clone(), + &mut tx, + ) + .await?; signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx).await?; Ok(()) } pub async fn submit_unjail_validator< C: namada::ledger::queries::Client + Sync, + IO: Io, >( client: &C, mut ctx: Context, @@ -1215,30 +1363,41 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, pk) = - tx::build_unjail_validator(client, &mut ctx.wallet, args.clone()) - .await?; - submit_reveal_aux(client, &mut ctx, &args.tx, addr, pk.clone(), &mut tx) - .await?; + let (mut tx, addr, pk) = tx::build_unjail_validator::<_, _, IO>( + client, + &mut ctx.wallet, + args.clone(), + ) + .await?; + submit_reveal_aux::<_, IO>( + client, + &mut ctx, + &args.tx, + addr, + pk.clone(), + &mut tx, + ) + .await?; signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx).await?; Ok(()) } /// Save accounts initialized from a tx into the wallet, if any. -pub async fn save_initialized_accounts( +pub async fn save_initialized_accounts( wallet: &mut Wallet, args: &args::Tx, initialized_accounts: Vec
, ) { - tx::save_initialized_accounts::(wallet, args, initialized_accounts).await + tx::save_initialized_accounts::(wallet, args, initialized_accounts) + .await } /// Broadcast a transaction to be included in the blockchain and checks that /// the tx has been successfully included into the mempool of a validator /// /// In the case of errors in any of those stages, an error message is returned -pub async fn broadcast_tx( +pub async fn broadcast_tx( rpc_cli: &C, to_broadcast: &TxBroadcastData, ) -> Result @@ -1246,7 +1405,7 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - tx::broadcast_tx(rpc_cli, to_broadcast).await + tx::broadcast_tx::<_, IO>(rpc_cli, to_broadcast).await } /// Broadcast a transaction to be included in the blockchain. @@ -1257,7 +1416,7 @@ where /// 3. The decrypted payload of the tx has been included on the blockchain. /// /// In the case of errors in any of those stages, an error message is returned -pub async fn submit_tx( +pub async fn submit_tx( client: &C, to_broadcast: TxBroadcastData, ) -> Result @@ -1265,7 +1424,7 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - tx::submit_tx(client, to_broadcast).await + tx::submit_tx::<_, IO>(client, to_broadcast).await } #[cfg(test)] diff --git a/shared/src/ledger/eth_bridge.rs b/shared/src/ledger/eth_bridge.rs index 50d560c2b0..e5b10f20db 100644 --- a/shared/src/ledger/eth_bridge.rs +++ b/shared/src/ledger/eth_bridge.rs @@ -17,6 +17,8 @@ use crate::types::control_flow::time::{ Constant, Duration, Error as TimeoutError, Instant, LinearBackoff, Sleep, }; use crate::types::control_flow::{self, Halt, TryHalt}; +use crate::types::io::Io; +use crate::{display_line, edisplay}; const DEFAULT_BACKOFF: Duration = std::time::Duration::from_millis(500); const DEFAULT_CEILING: Duration = std::time::Duration::from_secs(30); @@ -98,7 +100,10 @@ pub struct BlockOnEthSync { } /// Block until Ethereum finishes synchronizing. -pub async fn block_on_eth_sync(client: &C, args: BlockOnEthSync) -> Halt<()> +pub async fn block_on_eth_sync( + client: &C, + args: BlockOnEthSync, +) -> Halt<()> where C: Middleware, { @@ -106,7 +111,7 @@ where deadline, delta_sleep, } = args; - tracing::info!("Attempting to synchronize with the Ethereum network"); + display_line!(IO, "Attempting to synchronize with the Ethereum network"); Sleep { strategy: LinearBackoff { delta: delta_sleep }, } @@ -122,15 +127,15 @@ where }) .await .try_halt(|_| { - tracing::error!("Timed out while waiting for Ethereum to synchronize"); + edisplay!(IO, "Timed out while waiting for Ethereum to synchronize"); })?; - tracing::info!("The Ethereum node is up to date"); + display_line!(IO, "The Ethereum node is up to date"); control_flow::proceed(()) } /// Check if Ethereum has finished synchronizing. In case it has /// not, perform `action`. -pub async fn eth_sync_or( +pub async fn eth_sync_or( client: &C, mut action: F, ) -> Halt> @@ -142,7 +147,8 @@ where .await .map(|status| status.is_synchronized()) .try_halt(|err| { - tracing::error!( + edisplay!( + IO, "An error occurred while fetching the Ethereum \ synchronization status: {err}" ); @@ -156,11 +162,11 @@ where /// Check if Ethereum has finished synchronizing. In case it has /// not, end execution. -pub async fn eth_sync_or_exit(client: &C) -> Halt<()> +pub async fn eth_sync_or_exit(client: &C) -> Halt<()> where C: Middleware, { - eth_sync_or(client, || { + eth_sync_or::<_, _, _, IO>(client, || { tracing::error!("The Ethereum node has not finished synchronizing"); }) .await? diff --git a/shared/src/ledger/eth_bridge/bridge_pool.rs b/shared/src/ledger/eth_bridge/bridge_pool.rs index a95d56d475..47ce2453d8 100644 --- a/shared/src/ledger/eth_bridge/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/bridge_pool.rs @@ -2,7 +2,6 @@ use std::cmp::Ordering; use std::collections::HashMap; -use std::io::Write; use std::sync::Arc; use borsh::BorshSerialize; @@ -42,6 +41,7 @@ use crate::types::voting_power::FractionalVotingPower; pub async fn build_bridge_pool_tx< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -59,10 +59,15 @@ pub async fn build_bridge_pool_tx< } = args; 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 DenominatedAmount { amount, .. } = validate_amount::<_, IO>( + client, + amount, + &BRIDGE_ADDRESS, + &sub_prefix, + tx.force, + ) + .await + .expect("Failed to validate amount"); let transfer = PendingTransfer { transfer: TransferToEthereum { asset, @@ -87,7 +92,7 @@ pub async fn build_bridge_pool_tx< // TODO: change the wasm code to a hash transfer_tx.set_code(Code::new(wasm_code)); - prepare_tx::( + prepare_tx::( client, wallet, tx, @@ -108,7 +113,7 @@ struct BridgePoolResponse { /// Query the contents of the Ethereum bridge pool. /// Prints out a json payload. -pub async fn query_bridge_pool(client: &C) +pub async fn query_bridge_pool(client: &C) where C: Client + Sync, { @@ -123,19 +128,19 @@ where .map(|transfer| (transfer.keccak256().to_string(), transfer)) .collect(); if pool_contents.is_empty() { - println!("Bridge pool is empty."); + display_line!(IO, "Bridge pool is empty."); return; } let contents = BridgePoolResponse { bridge_pool_contents: pool_contents, }; - println!("{}", serde_json::to_string_pretty(&contents).unwrap()); + display_line!(IO, "{}", serde_json::to_string_pretty(&contents).unwrap()); } /// Query the contents of the Ethereum bridge pool that /// is covered by the latest signed root. /// Prints out a json payload. -pub async fn query_signed_bridge_pool( +pub async fn query_signed_bridge_pool( client: &C, ) -> Halt> where @@ -152,13 +157,13 @@ where .map(|transfer| (transfer.keccak256().to_string(), transfer)) .collect(); if pool_contents.is_empty() { - println!("Bridge pool is empty."); + display_line!(IO, "Bridge pool is empty."); return control_flow::halt(); } let contents = BridgePoolResponse { bridge_pool_contents: pool_contents.clone(), }; - println!("{}", serde_json::to_string_pretty(&contents).unwrap()); + display_line!(IO, "{}", serde_json::to_string_pretty(&contents).unwrap()); control_flow::proceed(pool_contents) } @@ -167,7 +172,7 @@ where /// backing each `TransferToEthereum` event. /// /// Prints a json payload. -pub async fn query_relay_progress(client: &C) +pub async fn query_relay_progress(client: &C) where C: Client + Sync, { @@ -177,12 +182,12 @@ where .transfer_to_ethereum_progress(client) .await .unwrap(); - println!("{}", serde_json::to_string_pretty(&resp).unwrap()); + display_line!(IO, "{}", serde_json::to_string_pretty(&resp).unwrap()); } /// Internal methdod to construct a proof that a set of transfers are in the /// bridge pool. -async fn construct_bridge_pool_proof( +async fn construct_bridge_pool_proof( client: &C, transfers: &[KeccakHash], relayer: Address, @@ -213,27 +218,29 @@ where let warning = "Warning".on_yellow(); let warning = warning.bold(); let warning = warning.blink(); - println!( + display_line!( + IO, "{warning}: The following hashes correspond to transfers that \ have surpassed the security threshold in Namada, therefore have \ likely been relayed to Ethereum, but do not yet have a quorum of \ validator signatures behind them in Namada; thus they are still \ in the Bridge pool:\n{warnings:?}", ); - print!("\nDo you wish to proceed? (y/n): "); - std::io::stdout().flush().unwrap(); + display!(IO, "\nDo you wish to proceed? (y/n): "); + IO::flush(); loop { - let mut buffer = String::new(); - let stdin = std::io::stdin(); - stdin.read_line(&mut buffer).try_halt(|e| { - println!("Encountered error reading from STDIN: {e:?}"); + let resp = IO::read().try_halt(|e| { + display_line!( + IO, + "Encountered error reading from STDIN: {e:?}" + ); })?; - match buffer.trim() { + match resp.trim() { "y" => break, "n" => return control_flow::halt(), _ => { - print!("Expected 'y' or 'n'. Please try again: "); - std::io::stdout().flush().unwrap(); + display!(IO, "Expected 'y' or 'n'. Please try again: "); + IO::flush(); } } } @@ -247,7 +254,7 @@ where .await; response.map(|response| response.data).try_halt(|e| { - println!("Encountered error constructing proof:\n{:?}", e); + display_line!(IO, "Encountered error constructing proof:\n{:?}", e); }) } @@ -263,14 +270,14 @@ struct BridgePoolProofResponse { /// Construct a merkle proof of a batch of transfers in /// the bridge pool and return it to the user (as opposed /// to relaying it to ethereum). -pub async fn construct_proof( +pub async fn construct_proof( client: &C, args: args::BridgePoolProof, ) -> Halt<()> where C: Client + Sync, { - let bp_proof_bytes = construct_bridge_pool_proof( + let bp_proof_bytes = construct_bridge_pool_proof::<_, IO>( client, &args.transfers, args.relayer.clone(), @@ -278,7 +285,11 @@ where .await?; let bp_proof: RelayProof = AbiDecode::decode(&bp_proof_bytes).try_halt(|error| { - println!("Unable to decode the generated proof: {:?}", error); + display_line!( + IO, + "Unable to decode the generated proof: {:?}", + error + ); })?; let resp = BridgePoolProofResponse { hashes: args.transfers, @@ -291,12 +302,12 @@ where .into(), abi_encoded_proof: bp_proof_bytes, }; - println!("{}", serde_json::to_string(&resp).unwrap()); + display_line!(IO, "{}", serde_json::to_string(&resp).unwrap()); control_flow::proceed(()) } /// Relay a validator set update, signed off for a given epoch. -pub async fn relay_bridge_pool_proof( +pub async fn relay_bridge_pool_proof( eth_client: Arc, nam_client: &C, args: args::RelayBridgePoolProof, @@ -309,7 +320,7 @@ where let _signal_receiver = args.safe_mode.then(install_shutdown_signal); if args.sync { - block_on_eth_sync( + block_on_eth_sync::<_, IO>( &*eth_client, BlockOnEthSync { deadline: Instant::now() + Duration::from_secs(60), @@ -318,12 +329,15 @@ where ) .await?; } else { - eth_sync_or_exit(&*eth_client).await?; + eth_sync_or_exit::<_, IO>(&*eth_client).await?; } - let bp_proof = - construct_bridge_pool_proof(nam_client, &args.transfers, args.relayer) - .await?; + let bp_proof = construct_bridge_pool_proof::<_, IO>( + nam_client, + &args.transfers, + args.relayer, + ) + .await?; let bridge = match RPC .shell() .eth_bridge() @@ -335,7 +349,8 @@ where let error = "Error".on_red(); let error = error.bold(); let error = error.blink(); - println!( + display_line!( + IO, "{error}: Failed to retrieve the Ethereum Bridge smart \ contract address from storage with \ reason:\n{err_msg}\n\nPerhaps the Ethereum bridge is not \ @@ -347,7 +362,11 @@ where let bp_proof: RelayProof = AbiDecode::decode(&bp_proof).try_halt(|error| { - println!("Unable to decode the generated proof: {:?}", error); + display_line!( + IO, + "Unable to decode the generated proof: {:?}", + error + ); })?; // NOTE: this operation costs no gas on Ethereum @@ -360,7 +379,8 @@ where let error = "Error".on_red(); let error = error.bold(); let error = error.blink(); - println!( + display_line!( + IO, "{error}: The Bridge pool nonce in the smart contract is \ {contract_nonce}, while the nonce in Namada is still {}. A \ relay of the former one has already happened, but a proof \ @@ -373,7 +393,8 @@ where let error = "Error".on_red(); let error = error.bold(); let error = error.blink(); - println!( + display_line!( + IO, "{error}: The Bridge pool nonce in the smart contract is \ {contract_nonce}, while the nonce in Namada is still {}. \ Somehow, Namada's nonce is ahead of the contract's nonce!", @@ -400,7 +421,7 @@ where .await .unwrap(); - println!("{transf_result:?}"); + display_line!(IO, "{transf_result:?}"); control_flow::proceed(()) } @@ -411,6 +432,7 @@ mod recommendations { use super::*; use crate::eth_bridge::storage::bridge_pool::get_signed_root_key; use crate::eth_bridge::storage::proof::BridgePoolRootProof; + use crate::types::io::Io; use crate::types::storage::BlockHeight; use crate::types::vote_extensions::validator_set_update::{ EthAddrBook, VotingPowersMap, VotingPowersMapExt, @@ -458,7 +480,7 @@ mod recommendations { /// Recommend the most economical batch of transfers to relay based /// on a conversion rate estimates from NAM to ETH and gas usage /// heuristics. - pub async fn recommend_batch( + pub async fn recommend_batch( client: &C, args: args::RecommendBatch, ) -> Halt<()> @@ -517,7 +539,7 @@ mod recommendations { // we don't recommend transfers that have already been relayed let mut contents: Vec<(String, I256, PendingTransfer)> = - query_signed_bridge_pool(client) + query_signed_bridge_pool::<_, IO>(client) .await? .into_iter() .filter_map(|(k, v)| { @@ -546,7 +568,7 @@ mod recommendations { let max_gas = args.max_gas.map(Uint::from_u64).unwrap_or(uint::MAX_VALUE); let max_cost = args.gas.map(I256::from).unwrap_or_default(); - generate(contents, validator_gas, max_gas, max_cost)?; + generate::(contents, validator_gas, max_gas, max_cost)?; control_flow::proceed(()) } @@ -587,7 +609,7 @@ mod recommendations { /// Generates the actual recommendation from restrictions given by the /// input parameters. - fn generate( + fn generate( contents: Vec<(String, I256, PendingTransfer)>, validator_gas: Uint, max_gas: Uint, @@ -644,16 +666,22 @@ mod recommendations { control_flow::proceed( if state.feasible_region && !recommendation.is_empty() { - println!("Recommended batch: {:#?}", recommendation); - println!( + display_line!(IO, "Recommended batch: {:#?}", recommendation); + display_line!( + IO, "Estimated Ethereum transaction gas (in gwei): {}", total_gas ); - println!("Estimated net profit (in gwei): {}", -total_cost); - println!("Total fees (in NAM): {}", total_fees); + display_line!( + IO, + "Estimated net profit (in gwei): {}", + -total_cost + ); + display_line!(IO, "Total fees (in NAM): {}", total_fees); Some(recommendation) } else { - println!( + display_line!( + IO, "Unable to find a recommendation satisfying the input \ parameters." ); @@ -669,6 +697,7 @@ mod recommendations { use super::*; use crate::types::control_flow::ProceedOrElse; + use crate::types::io::DefaultIo; /// An established user address for testing & development pub fn bertha_address() -> Address { @@ -757,7 +786,7 @@ mod recommendations { let profitable = vec![transfer(100_000); 17]; let hash = profitable[0].keccak256().to_string(); let expected = vec![hash; 17]; - let recommendation = generate( + let recommendation = generate::( process_transfers(profitable), Uint::from_u64(800_000), uint::MAX_VALUE, @@ -774,7 +803,7 @@ mod recommendations { let hash = transfers[0].keccak256().to_string(); transfers.push(transfer(0)); let expected: Vec<_> = vec![hash; 17]; - let recommendation = generate( + let recommendation = generate::( process_transfers(transfers), Uint::from_u64(800_000), uint::MAX_VALUE, @@ -790,7 +819,7 @@ mod recommendations { let transfers = vec![transfer(75_000); 4]; let hash = transfers[0].keccak256().to_string(); let expected = vec![hash; 2]; - let recommendation = generate( + let recommendation = generate::( process_transfers(transfers), Uint::from_u64(50_000), Uint::from_u64(150_000), @@ -810,7 +839,7 @@ mod recommendations { .map(|t| t.keccak256().to_string()) .take(5) .collect(); - let recommendation = generate( + let recommendation = generate::( process_transfers(transfers), Uint::from_u64(150_000), uint::MAX_VALUE, @@ -827,7 +856,7 @@ mod recommendations { let hash = transfers[0].keccak256().to_string(); let expected = vec![hash; 4]; transfers.extend([transfer(17_500), transfer(17_500)]); - let recommendation = generate( + let recommendation = generate::( process_transfers(transfers), Uint::from_u64(150_000), Uint::from_u64(330_000), @@ -841,7 +870,7 @@ mod recommendations { #[test] fn test_wholly_infeasible() { let transfers = vec![transfer(75_000); 4]; - let recommendation = generate( + let recommendation = generate::( process_transfers(transfers), Uint::from_u64(300_000), uint::MAX_VALUE, @@ -854,3 +883,6 @@ mod recommendations { } pub use recommendations::recommend_batch; + +use crate::types::io::Io; +use crate::{display, display_line}; diff --git a/shared/src/ledger/eth_bridge/validator_set.rs b/shared/src/ledger/eth_bridge/validator_set.rs index 6814fae8ec..d4c01f1c1a 100644 --- a/shared/src/ledger/eth_bridge/validator_set.rs +++ b/shared/src/ledger/eth_bridge/validator_set.rs @@ -24,6 +24,8 @@ use crate::types::control_flow::time::{self, Duration, Instant}; use crate::types::control_flow::{ self, install_shutdown_signal, Halt, TryHalt, }; +use crate::types::io::{DefaultIo, Io}; +use crate::{display_line, edisplay}; /// Relayer related errors. #[derive(Debug, Default)] @@ -253,7 +255,7 @@ impl From> for RelayResult { /// Query an ABI encoding of the validator set to be installed /// at the given epoch, and its associated proof. -pub async fn query_validator_set_update_proof( +pub async fn query_validator_set_update_proof( client: &C, args: args::ValidatorSetProof, ) where @@ -272,11 +274,11 @@ pub async fn query_validator_set_update_proof( .await .unwrap(); - println!("0x{}", HEXLOWER.encode(encoded_proof.as_ref())); + display_line!(IO, "0x{}", HEXLOWER.encode(encoded_proof.as_ref())); } /// Query an ABI encoding of the validator set at a given epoch. -pub async fn query_validator_set_args( +pub async fn query_validator_set_args( client: &C, args: args::ConsensusValidatorSet, ) where @@ -295,11 +297,15 @@ pub async fn query_validator_set_args( .await .unwrap(); - println!("0x{}", HEXLOWER.encode(encoded_validator_set_args.as_ref())); + display_line!( + IO, + "0x{}", + HEXLOWER.encode(encoded_validator_set_args.as_ref()) + ); } /// Relay a validator set update, signed off for a given epoch. -pub async fn relay_validator_set_update( +pub async fn relay_validator_set_update( eth_client: Arc, nam_client: &C, args: args::ValidatorSetUpdateRelay, @@ -312,7 +318,7 @@ where let mut signal_receiver = args.safe_mode.then(install_shutdown_signal); if args.sync { - block_on_eth_sync( + block_on_eth_sync::<_, IO>( &*eth_client, BlockOnEthSync { deadline: Instant::now() + Duration::from_secs(60), @@ -321,7 +327,7 @@ where ) .await?; } else { - eth_sync_or_exit(&*eth_client).await?; + eth_sync_or_exit::<_, IO>(&*eth_client).await?; } if args.daemon { @@ -339,7 +345,7 @@ where nam_client, |relay_result| match relay_result { RelayResult::GovernanceCallError(reason) => { - tracing::error!(reason, "Calling Governance failed"); + edisplay!(IO, "Calling Governance failed due to: {reason}"); } RelayResult::NonceError { argument, contract } => { let whence = match argument.cmp(&contract) { @@ -347,22 +353,31 @@ where Ordering::Equal => "identical to", Ordering::Greater => "too far ahead of", }; - tracing::error!( - ?argument, - ?contract, - "Argument nonce is {whence} contract nonce" + edisplay!( + IO, + "Argument nonce <{argument}> is {whence} contract \ + nonce <{contract}>" ); } RelayResult::NoReceipt => { - tracing::warn!( + edisplay!( + IO, "No transfer receipt received from the Ethereum node" ); } RelayResult::Receipt { receipt } => { if receipt.is_successful() { - tracing::info!(?receipt, "Ethereum transfer succeded"); + display_line!( + IO, + "Ethereum transfer succeded: {:?}", + receipt + ); } else { - tracing::error!(?receipt, "Ethereum transfer failed"); + display_line!( + IO, + "Ethereum transfer failed: {:?}", + receipt + ); } } }, @@ -420,7 +435,9 @@ where time::sleep(sleep_for).await; let is_synchronizing = - eth_sync_or(&*eth_client, || ()).await.is_break(); + eth_sync_or::<_, _, _, DefaultIo>(&*eth_client, || ()) + .await + .is_break(); if is_synchronizing { tracing::debug!("The Ethereum node is synchronizing"); last_call_succeeded = false; diff --git a/shared/src/ledger/masp.rs b/shared/src/ledger/masp.rs index 28e1fd8e13..f92847b213 100644 --- a/shared/src/ledger/masp.rs +++ b/shared/src/ledger/masp.rs @@ -67,6 +67,7 @@ use crate::proto::Tx; use crate::tendermint_rpc::query::Query; use crate::tendermint_rpc::Order; use crate::types::address::{masp, Address}; +use crate::types::io::Io; use crate::types::masp::{BalanceOwner, ExtendedViewingKey, PaymentAddress}; use crate::types::storage::{BlockHeight, Epoch, Key, KeySeg, TxIndex}; use crate::types::token; @@ -74,6 +75,7 @@ use crate::types::token::{ Transfer, HEAD_TX_KEY, PIN_KEY_PREFIX, TX_KEY_PREFIX, }; use crate::types::transaction::{EllipticCurve, PairingEngine, WrapperTx}; +use crate::{display_line, edisplay}; /// Env var to point to a dir with MASP parameters. When not specified, /// the default OS specific path is used. @@ -960,7 +962,7 @@ impl ShieldedContext { /// context and express that value in terms of the currently timestamped /// asset types. If the key is not in the context, then we do not know the /// balance and hence we return None. - pub async fn compute_exchanged_balance( + pub async fn compute_exchanged_balance( &mut self, client: &C, vk: &ViewingKey, @@ -969,7 +971,7 @@ impl ShieldedContext { // First get the unexchanged balance if let Some(balance) = self.compute_shielded_balance(client, vk).await { let exchanged_amount = self - .compute_exchanged_amount( + .compute_exchanged_amount::<_, IO>( client, balance, target_epoch, @@ -990,7 +992,7 @@ impl ShieldedContext { /// the trace amount that could not be converted is moved from input to /// output. #[allow(clippy::too_many_arguments)] - async fn apply_conversion( + async fn apply_conversion( &mut self, client: &C, conv: AllowedConversion, @@ -1015,7 +1017,8 @@ impl ShieldedContext { ); let threshold = -conv[&masp_asset]; if threshold == 0 { - eprintln!( + edisplay!( + IO, "Asset threshold of selected conversion for asset type {} is \ 0, this is a bug, please report it.", masp_asset @@ -1044,7 +1047,7 @@ impl ShieldedContext { /// note of the conversions that were used. Note that this function does /// not assume that allowed conversions from the ledger are expressed in /// terms of the latest asset types. - pub async fn compute_exchanged_amount( + pub async fn compute_exchanged_amount( &mut self, client: &C, mut input: MaspAmount, @@ -1090,14 +1093,15 @@ impl ShieldedContext { if let (Some((conv, _wit, usage)), false) = (conversions.get_mut(&asset_type), at_target_asset_type) { - println!( + display_line!( + IO, "converting current asset type to latest asset type..." ); // Not at the target asset type, not at the latest asset // type. Apply conversion to get from // current asset type to the latest // asset type. - self.apply_conversion( + self.apply_conversion::<_, IO>( client, conv.clone(), (asset_epoch, token_addr.clone(), denom), @@ -1111,14 +1115,15 @@ impl ShieldedContext { conversions.get_mut(&target_asset_type), at_target_asset_type, ) { - println!( + display_line!( + IO, "converting latest asset type to target asset type..." ); // Not at the target asset type, yet at the latest asset // type. Apply inverse conversion to get // from latest asset type to the target // asset type. - self.apply_conversion( + self.apply_conversion::<_, IO>( client, conv.clone(), (asset_epoch, token_addr.clone(), denom), @@ -1153,7 +1158,7 @@ impl ShieldedContext { /// of the specified asset type. Return the total value accumulated plus /// notes and the corresponding diversifiers/merkle paths that were used to /// achieve the total value. - pub async fn collect_unspent_notes( + pub async fn collect_unspent_notes( &mut self, client: &C, vk: &ViewingKey, @@ -1188,7 +1193,7 @@ impl ShieldedContext { .expect("received note has invalid value or asset type"); let input = self.decode_all_amounts(client, pre_contr).await; let (contr, proposed_convs) = self - .compute_exchanged_amount( + .compute_exchanged_amount::<_, IO>( client, input, target_epoch, @@ -1294,7 +1299,7 @@ impl ShieldedContext { /// the epoch of the transaction or even before, so exchange all these /// amounts to the epoch of the transaction in order to get the value that /// would have been displayed in the epoch of the transaction. - pub async fn compute_exchanged_pinned_balance( + pub async fn compute_exchanged_pinned_balance( &mut self, client: &C, owner: PaymentAddress, @@ -1303,16 +1308,21 @@ impl ShieldedContext { // Obtain the balance that will be exchanged let (amt, ep) = Self::compute_pinned_balance(client, owner, viewing_key).await?; - println!("Pinned balance: {:?}", amt); + display_line!(IO, "Pinned balance: {:?}", amt); // Establish connection with which to do exchange rate queries let amount = self.decode_all_amounts(client, amt).await; - println!("Decoded pinned balance: {:?}", amount); + display_line!(IO, "Decoded pinned balance: {:?}", amount); // Finally, exchange the balance to the transaction's epoch let computed_amount = self - .compute_exchanged_amount(client, amount, ep, HashMap::new()) + .compute_exchanged_amount::<_, IO>( + client, + amount, + ep, + HashMap::new(), + ) .await .0; - println!("Exchanged amount: {:?}", computed_amount); + display_line!(IO, "Exchanged amount: {:?}", computed_amount); Ok((self.decode_all_amounts(client, computed_amount).await, ep)) } @@ -1391,7 +1401,7 @@ impl ShieldedContext { /// understood that transparent account changes are effected only by the /// amounts and signatures specified by the containing Transfer object. #[cfg(feature = "masp-tx-gen")] - pub async fn gen_shielded_transfer( + pub async fn gen_shielded_transfer( &mut self, client: &C, args: &args::TxTransfer, @@ -1462,7 +1472,7 @@ impl ShieldedContext { // Locate unspent notes that can help us meet the transaction amount let (_, unspent_notes, used_convs) = self - .collect_unspent_notes( + .collect_unspent_notes::<_, IO>( client, &to_viewing_key(&sk).vk, required_amt, diff --git a/shared/src/ledger/rpc.rs b/shared/src/ledger/rpc.rs index 90d05ebd13..357ab8d298 100644 --- a/shared/src/ledger/rpc.rs +++ b/shared/src/ledger/rpc.rs @@ -34,16 +34,18 @@ use crate::tendermint_rpc::Order; use crate::types::control_flow::{time, Halt, TryHalt}; use crate::types::governance::{ProposalVote, VotePower}; use crate::types::hash::Hash; +use crate::types::io::Io; use crate::types::key::*; use crate::types::storage::{BlockHeight, BlockResults, Epoch, PrefixValue}; use crate::types::token::balance_key; use crate::types::{storage, token}; +use crate::{display_line, edisplay}; /// Query the status of a given transaction. /// /// If a response is not delivered until `deadline`, we exit the cli with an /// error. -pub async fn query_tx_status( +pub async fn query_tx_status( client: &C, status: TxEventQuery<'_>, deadline: time::Instant, @@ -84,7 +86,10 @@ where }) .await .try_halt(|_| { - eprintln!("Transaction status query deadline of {deadline:?} exceeded"); + edisplay!( + IO, + "Transaction status query deadline of {deadline:?} exceeded" + ); }) } @@ -253,7 +258,10 @@ pub async fn query_conversion( } /// Query a wasm code hash -pub async fn query_wasm_code_hash( +pub async fn query_wasm_code_hash< + C: crate::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, code_path: impl AsRef, ) -> Option { @@ -266,7 +274,8 @@ pub async fn query_wasm_code_hash( Some(Hash::try_from(&hash[..]).expect("Invalid code hash")) } None => { - eprintln!( + edisplay!( + IO, "The corresponding wasm code of the code path {} doesn't \ exist on chain.", code_path.as_ref(), @@ -339,7 +348,11 @@ pub async fn query_storage_value_bytes< /// Query a range of storage values with a matching prefix and decode them with /// [`BorshDeserialize`]. Returns an iterator of the storage keys paired with /// their associated values. -pub async fn query_storage_prefix( +pub async fn query_storage_prefix< + C: crate::ledger::queries::Client + Sync, + IO: Io, + T, +>( client: &C, key: &storage::Key, ) -> Option> @@ -356,9 +369,11 @@ where &value[..], ) { Err(err) => { - eprintln!( + edisplay!( + IO, "Skipping a value for key {}. Error in decoding: {}", - key, err + key, + err ); None } @@ -446,7 +461,7 @@ pub async fn query_tx_events( } /// Dry run a transaction -pub async fn dry_run_tx( +pub async fn dry_run_tx( client: &C, tx_bytes: Vec, ) -> namada_core::types::transaction::TxResult { @@ -455,7 +470,7 @@ pub async fn dry_run_tx( RPC.shell().dry_run_tx(client, data, height, prove).await, ) .data; - println! {"Dry-run result: {}", result}; + display_line!(IO, "Dry-run result: {}", result); result } @@ -634,7 +649,10 @@ pub async fn query_tx_response( } /// Get the votes for a given proposal id -pub async fn get_proposal_votes( +pub async fn get_proposal_votes< + C: crate::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, epoch: Epoch, proposal_id: u64, @@ -644,7 +662,8 @@ pub async fn get_proposal_votes( let vote_prefix_key = gov_storage::get_proposal_vote_prefix_key(proposal_id); let vote_iter = - query_storage_prefix::(client, &vote_prefix_key).await; + query_storage_prefix::(client, &vote_prefix_key) + .await; let mut yay_validators: HashMap = HashMap::new(); @@ -778,6 +797,7 @@ pub async fn query_bond( /// Query a validator's unbonds for a given epoch pub async fn query_and_print_unbonds< C: crate::ledger::queries::Client + Sync, + IO: Io, >( client: &C, source: &Address, @@ -798,16 +818,18 @@ pub async fn query_and_print_unbonds< } } if total_withdrawable != token::Amount::default() { - println!( + display_line!( + IO, "Total withdrawable now: {}.", total_withdrawable.to_string_native() ); } if !not_yet_withdrawable.is_empty() { - println!("Current epoch: {current_epoch}.") + display_line!(IO, "Current epoch: {current_epoch}.") } for (withdraw_epoch, amount) in not_yet_withdrawable { - println!( + display_line!( + IO, "Amount {} withdrawable starting from epoch {withdraw_epoch}.", amount.to_string_native() ); @@ -950,7 +972,10 @@ pub async fn enriched_bonds_and_unbonds< } /// Get the correct representation of the amount given the token type. -pub async fn validate_amount( +pub async fn validate_amount< + C: crate::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, amount: InputAmount, token: &Address, @@ -969,13 +994,15 @@ pub async fn validate_amount( ) .or_else(|| { if force { - println!( + display_line!( + IO, "No denomination found for token: {token}, but --force was \ passed. Defaulting to the provided denomination." ); Some(input_amount.denom) } else { - println!( + display_line!( + IO, "No denomination found for token: {token}, the input \ arguments could not be parsed." ); @@ -983,7 +1010,8 @@ pub async fn validate_amount( } })?; if denom < input_amount.denom && !force { - println!( + display_line!( + IO, "The input amount contained a higher precision than allowed by \ {token}." ); @@ -992,7 +1020,8 @@ pub async fn validate_amount( match input_amount.increase_precision(denom) { Ok(res) => Some(res), Err(_) => { - println!( + display_line!( + IO, "The amount provided requires more the 256 bits to \ represent." ); @@ -1003,7 +1032,7 @@ pub async fn validate_amount( } /// Wait for a first block and node to be synced. -pub async fn wait_until_node_is_synched(client: &C) -> Halt<()> +pub async fn wait_until_node_is_synched(client: &C) -> Halt<()> where C: crate::ledger::queries::Client + Sync, { @@ -1027,7 +1056,8 @@ where if is_at_least_height_one && !is_catching_up { return ControlFlow::Break(Ok(())); } - println!( + display_line!( + IO, " Waiting for {} ({}/{} tries)...", if is_at_least_height_one { "a first block" @@ -1041,7 +1071,7 @@ where ControlFlow::Continue(()) } Err(e) => { - eprintln!("Failed to query node status with error: {}", e); + edisplay!(IO, "Failed to query node status with error: {}", e); ControlFlow::Break(Err(())) } } @@ -1049,7 +1079,10 @@ where .await // maybe time out .try_halt(|_| { - println!("Node is still catching up, wait for it to finish synching."); + display_line!( + IO, + "Node is still catching up, wait for it to finish synching." + ); })? // error querying rpc .try_halt(|_| ()) @@ -1059,6 +1092,7 @@ where /// correctly as a string. pub async fn format_denominated_amount< C: crate::ledger::queries::Client + Sync, + IO: Io, >( client: &C, token: &TokenAddress, @@ -1071,7 +1105,8 @@ pub async fn format_denominated_amount< .await, ) .unwrap_or_else(|| { - println!( + display_line!( + IO, "No denomination found for token: {token}, defaulting to zero \ decimal places" ); diff --git a/shared/src/ledger/signing.rs b/shared/src/ledger/signing.rs index b6b06f0dae..a7204bcce4 100644 --- a/shared/src/ledger/signing.rs +++ b/shared/src/ledger/signing.rs @@ -46,6 +46,7 @@ pub use crate::ledger::wallet::store::AddressVpType; use crate::ledger::wallet::{Wallet, WalletUtils}; use crate::ledger::{args, rpc}; use crate::proto::{MaspBuilder, Section, Signature, Tx}; +use crate::types::io::Io; use crate::types::key::*; use crate::types::masp::{ExtendedViewingKey, PaymentAddress}; use crate::types::storage::Epoch; @@ -56,6 +57,7 @@ use crate::types::transaction::governance::{ use crate::types::transaction::{ Fee, InitAccount, InitValidator, TxType, UpdateVp, WrapperTx, }; +use crate::{display_line, edisplay}; #[cfg(feature = "std")] /// Env. var specifying where to store signing test vectors @@ -71,6 +73,7 @@ const ENV_VAR_TX_LOG_PATH: &str = "NAMADA_TX_LOG_PATH"; pub async fn find_pk< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -79,7 +82,8 @@ pub async fn find_pk< ) -> Result { match addr { Address::Established(_) => { - println!( + display_line!( + IO, "Looking-up public key of {} from the ledger...", addr.encode() ); @@ -158,6 +162,7 @@ pub enum TxSigningKey { pub async fn tx_signer< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -186,7 +191,7 @@ pub async fn tx_signer< } TxSigningKey::WalletAddress(signer) => Ok(( Some(signer.clone()), - find_pk::(client, wallet, &signer, args.password.clone()) + find_pk::(client, wallet, &signer, args.password.clone()) .await?, )), TxSigningKey::None => other_err( @@ -230,7 +235,10 @@ pub async fn sign_tx( #[cfg(not(feature = "mainnet"))] /// Solve the PoW challenge if balance is insufficient to pay transaction fees /// or if solution is explicitly requested. -pub async fn solve_pow_challenge( +pub async fn solve_pow_challenge< + C: crate::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, args: &args::Tx, keypair: &common::PublicKey, @@ -259,8 +267,10 @@ pub async fn solve_pow_challenge( let err_msg = format!( "The wrapper transaction source doesn't have enough balance to \ pay fee {}, got {}.", - format_denominated_amount(client, &token_addr, fee_amount).await, - format_denominated_amount(client, &token_addr, balance).await, + format_denominated_amount::<_, IO>(client, &token_addr, fee_amount) + .await, + format_denominated_amount::<_, IO>(client, &token_addr, balance) + .await, ); if !args.force && cfg!(feature = "mainnet") { panic!("{}", err_msg); @@ -274,7 +284,10 @@ pub async fn solve_pow_challenge( // If the address derived from the keypair doesn't have enough balance // to pay for the fee, allow to find a PoW solution instead. if requires_pow || !is_bal_sufficient { - println!("The transaction requires the completion of a PoW challenge."); + display_line!( + IO, + "The transaction requires the completion of a PoW challenge." + ); // Obtain a PoW challenge for faucet withdrawal let challenge = rpc::get_testnet_pow_challenge(client, source).await; @@ -288,7 +301,10 @@ pub async fn solve_pow_challenge( #[cfg(not(feature = "mainnet"))] /// Update the PoW challenge inside the given transaction -pub async fn update_pow_challenge( +pub async fn update_pow_challenge< + C: crate::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, args: &args::Tx, tx: &mut Tx, @@ -297,7 +313,8 @@ pub async fn update_pow_challenge( ) { if let TxType::Wrapper(wrapper) = &mut tx.header.tx_type { let (pow_solution, fee) = - solve_pow_challenge(client, args, keypair, requires_pow).await; + solve_pow_challenge::<_, IO>(client, args, keypair, requires_pow) + .await; wrapper.fee = fee; wrapper.pow_solution = pow_solution; } @@ -309,6 +326,7 @@ pub async fn update_pow_challenge( pub async fn wrap_tx< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, #[allow(unused_variables)] wallet: &mut Wallet, @@ -320,7 +338,7 @@ pub async fn wrap_tx< ) -> Tx { #[cfg(not(feature = "mainnet"))] let (pow_solution, fee) = - solve_pow_challenge(client, args, keypair, requires_pow).await; + solve_pow_challenge::<_, IO>(client, args, keypair, requires_pow).await; // This object governs how the payload will be processed tx.update_header(TxType::Wrapper(Box::new(WrapperTx::new( fee, @@ -340,7 +358,7 @@ pub async fn wrap_tx< // 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) + let decoding = to_ledger_vector::<_, _, IO>(client, wallet, &tx) .await .expect("unable to decode transaction"); let output = serde_json::to_string(&decoding) @@ -378,6 +396,7 @@ pub async fn wrap_tx< pub async fn sign_wrapper< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, #[allow(unused_variables)] wallet: &mut Wallet, @@ -414,10 +433,12 @@ pub async fn sign_wrapper< let err_msg = format!( "The wrapper transaction source doesn't have enough balance to \ pay fee {}, got {}.", - format_denominated_amount(client, &token_addr, fee_amount).await, - format_denominated_amount(client, &token_addr, balance).await, + format_denominated_amount::<_, IO>(client, &token_addr, fee_amount) + .await, + format_denominated_amount::<_, IO>(client, &token_addr, balance) + .await, ); - eprintln!("{}", err_msg); + edisplay!(IO, "{}", err_msg); if !args.force && cfg!(feature = "mainnet") { panic!("{}", err_msg); } @@ -429,7 +450,8 @@ pub async fn sign_wrapper< // If the address derived from the keypair doesn't have enough balance // to pay for the fee, allow to find a PoW solution instead. if requires_pow || !is_bal_sufficient { - println!( + display_line!( + IO, "The transaction requires the completion of a PoW challenge." ); // Obtain a PoW challenge for faucet withdrawal @@ -466,7 +488,7 @@ pub async fn sign_wrapper< // 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) + let decoding = to_ledger_vector::<_, _, IO>(client, wallet, &tx) .await .expect("unable to decode transaction"); let output = serde_json::to_string(&decoding) @@ -561,7 +583,10 @@ fn make_ledger_amount_addr( /// Adds a Ledger output line describing a given transaction amount and asset /// type -async fn make_ledger_amount_asset( +async fn make_ledger_amount_asset< + C: crate::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, tokens: &HashMap, output: &mut Vec, @@ -576,8 +601,12 @@ async fn make_ledger_amount_asset( address: token.clone(), sub_prefix: sub_prefix.clone(), }; - let formatted_amt = - format_denominated_amount(client, &token_addr, amount.into()).await; + let formatted_amt = format_denominated_amount::<_, IO>( + client, + &token_addr, + amount.into(), + ) + .await; if let Some(token) = tokens.get(token) { output.push(format!( "{}Amount: {} {}", @@ -665,6 +694,7 @@ fn format_outputs(output: &mut Vec) { /// transactions pub async fn make_ledger_masp_endpoints< C: crate::ledger::queries::Client + Sync, + IO: Io, >( client: &C, tokens: &HashMap, @@ -689,7 +719,7 @@ pub async fn make_ledger_masp_endpoints< for sapling_input in builder.builder.sapling_inputs() { let vk = ExtendedViewingKey::from(*sapling_input.key()); output.push(format!("Sender : {}", vk)); - make_ledger_amount_asset( + make_ledger_amount_asset::<_, IO>( client, tokens, output, @@ -717,7 +747,7 @@ pub async fn make_ledger_masp_endpoints< for sapling_output in builder.builder.sapling_outputs() { let pa = PaymentAddress::from(sapling_output.address()); output.push(format!("Destination : {}", pa)); - make_ledger_amount_asset( + make_ledger_amount_asset::<_, IO>( client, tokens, output, @@ -746,44 +776,57 @@ pub async fn make_ledger_masp_endpoints< pub async fn to_ledger_vector< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, tx: &Tx, ) -> Result { - let init_account_hash = query_wasm_code_hash(client, TX_INIT_ACCOUNT_WASM) + let init_account_hash = + query_wasm_code_hash::<_, IO>(client, TX_INIT_ACCOUNT_WASM) + .await + .unwrap(); + let init_validator_hash = + query_wasm_code_hash::<_, IO>(client, TX_INIT_VALIDATOR_WASM) + .await + .unwrap(); + let init_proposal_hash = + query_wasm_code_hash::<_, IO>(client, TX_INIT_PROPOSAL) + .await + .unwrap(); + let vote_proposal_hash = + query_wasm_code_hash::<_, IO>(client, TX_VOTE_PROPOSAL) + .await + .unwrap(); + let reveal_pk_hash = query_wasm_code_hash::<_, IO>(client, TX_REVEAL_PK) .await .unwrap(); - let init_validator_hash = - query_wasm_code_hash(client, TX_INIT_VALIDATOR_WASM) + let update_vp_hash = + query_wasm_code_hash::<_, IO>(client, TX_UPDATE_VP_WASM) .await .unwrap(); - let init_proposal_hash = query_wasm_code_hash(client, TX_INIT_PROPOSAL) + let transfer_hash = query_wasm_code_hash::<_, IO>(client, TX_TRANSFER_WASM) .await .unwrap(); - let vote_proposal_hash = query_wasm_code_hash(client, TX_VOTE_PROPOSAL) + let ibc_hash = query_wasm_code_hash::<_, IO>(client, TX_IBC_WASM) .await .unwrap(); - let reveal_pk_hash = - query_wasm_code_hash(client, TX_REVEAL_PK).await.unwrap(); - let update_vp_hash = query_wasm_code_hash(client, TX_UPDATE_VP_WASM) + let bond_hash = query_wasm_code_hash::<_, IO>(client, TX_BOND_WASM) .await .unwrap(); - let transfer_hash = query_wasm_code_hash(client, TX_TRANSFER_WASM) + let unbond_hash = query_wasm_code_hash::<_, IO>(client, TX_UNBOND_WASM) .await .unwrap(); - let ibc_hash = query_wasm_code_hash(client, TX_IBC_WASM).await.unwrap(); - let bond_hash = query_wasm_code_hash(client, TX_BOND_WASM).await.unwrap(); - let unbond_hash = - query_wasm_code_hash(client, TX_UNBOND_WASM).await.unwrap(); - let withdraw_hash = query_wasm_code_hash(client, TX_WITHDRAW_WASM) + let withdraw_hash = query_wasm_code_hash::<_, IO>(client, TX_WITHDRAW_WASM) .await .unwrap(); let change_commission_hash = - query_wasm_code_hash(client, TX_CHANGE_COMMISSION_WASM) + query_wasm_code_hash::<_, IO>(client, TX_CHANGE_COMMISSION_WASM) .await .unwrap(); - let user_hash = query_wasm_code_hash(client, VP_USER_WASM).await.unwrap(); + let user_hash = query_wasm_code_hash::<_, IO>(client, VP_USER_WASM) + .await + .unwrap(); // To facilitate lookups of human-readable token names let tokens: HashMap = wallet @@ -1045,7 +1088,7 @@ pub async fn to_ledger_vector< tv.name = "Transfer 0".to_string(); tv.output.push("Type : Transfer".to_string()); - make_ledger_masp_endpoints( + make_ledger_masp_endpoints::<_, IO>( client, &tokens, &mut tv.output, @@ -1054,7 +1097,7 @@ pub async fn to_ledger_vector< &asset_types, ) .await; - make_ledger_masp_endpoints( + make_ledger_masp_endpoints::<_, IO>( client, &tokens, &mut tv.output_expert, @@ -1220,15 +1263,18 @@ pub async fn to_ledger_vector< address: wrapper.fee.token.clone(), sub_prefix: None, }; - let gas_limit = format_denominated_amount( + let gas_limit = format_denominated_amount::<_, IO>( client, &gas_token, Amount::from(wrapper.gas_limit), ) .await; - let gas_amount = - format_denominated_amount(client, &gas_token, wrapper.fee.amount) - .await; + let gas_amount = format_denominated_amount::<_, IO>( + client, + &gas_token, + wrapper.fee.amount, + ) + .await; tv.output_expert.extend(vec![ format!("Timestamp : {}", tx.header.timestamp.0), format!("PK : {}", wrapper.pk), diff --git a/shared/src/ledger/tx.rs b/shared/src/ledger/tx.rs index 7bceb09a09..85abe4ef30 100644 --- a/shared/src/ledger/tx.rs +++ b/shared/src/ledger/tx.rs @@ -42,14 +42,15 @@ use crate::proto::{Code, Data, MaspBuilder, Section, 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}; +use crate::types::io::Io; use crate::types::key::*; use crate::types::masp::TransferTarget; use crate::types::storage::{Epoch, RESERVED_ADDRESS_PREFIX}; use crate::types::time::DateTimeUtc; use crate::types::transaction::{pos, InitAccount, TxType, UpdateVp}; use crate::types::{storage, token}; -use crate::vm; use crate::vm::WasmValidationError; +use crate::{display_line, edisplay, vm}; /// Initialize account transaction WASM pub const TX_INIT_ACCOUNT_WASM: &str = "tx_init_account.wasm"; @@ -236,6 +237,7 @@ impl ProcessTxResponse { pub async fn prepare_tx< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -245,13 +247,14 @@ pub async fn prepare_tx< #[cfg(not(feature = "mainnet"))] requires_pow: bool, ) -> Result<(Tx, Option
, common::PublicKey), Error> { let (signer_addr, signer_pk) = - tx_signer::(client, wallet, args, default_signer.clone()).await?; + tx_signer::(client, wallet, args, default_signer.clone()) + .await?; if args.dry_run { Ok((tx, signer_addr, signer_pk)) } else { let epoch = rpc::query_epoch(client).await; Ok(( - wrap_tx( + wrap_tx::<_, _, IO>( client, wallet, args, @@ -273,6 +276,7 @@ pub async fn prepare_tx< pub async fn process_tx< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -292,7 +296,7 @@ pub async fn process_tx< // println!("HTTP request body: {}", request_body); if args.dry_run { - expect_dry_broadcast(TxBroadcastData::DryRun(tx), client).await + expect_dry_broadcast::<_, IO>(TxBroadcastData::DryRun(tx), client).await } else { // We use this to determine when the wrapper tx makes it on-chain let wrapper_hash = tx.header_hash().to_string(); @@ -311,13 +315,13 @@ pub async fn process_tx< // Either broadcast or submit transaction and collect result into // sum type if args.broadcast_only { - broadcast_tx(client, &to_broadcast) + broadcast_tx::<_, IO>(client, &to_broadcast) .await .map(ProcessTxResponse::Broadcast) } else { - match submit_tx(client, to_broadcast).await { + match submit_tx::<_, IO>(client, to_broadcast).await { Ok(x) => { - save_initialized_accounts::( + save_initialized_accounts::( wallet, args, x.initialized_accounts.clone(), @@ -335,6 +339,7 @@ pub async fn process_tx< pub async fn build_reveal_pk< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -347,12 +352,12 @@ pub async fn build_reveal_pk< 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."); + display_line!(IO, "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) + build_reveal_pk_aux::(client, wallet, &public_key, &args) .await?, )) } @@ -388,6 +393,7 @@ pub async fn has_revealed_pk( pub async fn build_reveal_pk_aux< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -395,10 +401,13 @@ pub async fn build_reveal_pk_aux< args: &args::Tx, ) -> Result<(Tx, Option
, common::PublicKey), Error> { let addr: Address = public_key.into(); - println!("Submitting a tx to reveal the public key for address {addr}..."); + display_line!( + IO, + "Submitting a tx to reveal the public key for address {addr}..." + ); let tx_data = public_key.try_to_vec().map_err(Error::EncodeKeyFailure)?; - let tx_code_hash = query_wasm_code_hash( + let tx_code_hash = query_wasm_code_hash::<_, IO>( client, args.tx_reveal_code_path.to_str().unwrap(), ) @@ -411,7 +420,7 @@ pub async fn build_reveal_pk_aux< tx.set_data(Data::new(tx_data)); tx.set_code(Code::from_hash(tx_code_hash)); - prepare_tx::( + prepare_tx::( client, wallet, args, @@ -427,7 +436,7 @@ pub async fn build_reveal_pk_aux< /// the tx has been successfully included into the mempool of a validator /// /// In the case of errors in any of those stages, an error message is returned -pub async fn broadcast_tx( +pub async fn broadcast_tx( rpc_cli: &C, to_broadcast: &TxBroadcastData, ) -> Result { @@ -452,12 +461,20 @@ pub async fn broadcast_tx( lift_rpc_error(rpc_cli.broadcast_tx_sync(tx.to_bytes().into()).await)?; if response.code == 0.into() { - println!("Transaction added to mempool: {:?}", response); + display_line!(IO, "Transaction added to mempool: {:?}", response); // Print the transaction identifiers to enable the extraction of // acceptance/application results later { - println!("Wrapper transaction hash: {:?}", wrapper_tx_hash); - println!("Inner transaction hash: {:?}", decrypted_tx_hash); + display_line!( + IO, + "Wrapper transaction hash: {:?}", + wrapper_tx_hash + ); + display_line!( + IO, + "Inner transaction hash: {:?}", + decrypted_tx_hash + ); } Ok(response) } else { @@ -475,7 +492,7 @@ pub async fn broadcast_tx( /// 3. The decrypted payload of the tx has been included on the blockchain. /// /// In the case of errors in any of those stages, an error message is returned -pub async fn submit_tx( +pub async fn submit_tx( client: &C, to_broadcast: TxBroadcastData, ) -> Result @@ -492,7 +509,7 @@ where }?; // Broadcast the supplied transaction - broadcast_tx(client, &to_broadcast).await?; + broadcast_tx::<_, IO>(client, &to_broadcast).await?; let deadline = time::Instant::now() + time::Duration::from_secs( @@ -508,12 +525,14 @@ where let parsed = { let wrapper_query = crate::ledger::rpc::TxEventQuery::Accepted(wrapper_hash.as_str()); - let event = rpc::query_tx_status(client, wrapper_query, deadline) - .await - .proceed_or(Error::AcceptTimeout)?; + let event = + rpc::query_tx_status::<_, IO>(client, wrapper_query, deadline) + .await + .proceed_or(Error::AcceptTimeout)?; let parsed = TxResponse::from_event(event); - println!( + display_line!( + IO, "Transaction accepted with result: {}", serde_json::to_string_pretty(&parsed).unwrap() ); @@ -524,11 +543,16 @@ where // payload makes its way onto the blockchain let decrypted_query = rpc::TxEventQuery::Applied(decrypted_hash.as_str()); - let event = rpc::query_tx_status(client, decrypted_query, deadline) - .await - .proceed_or(Error::AppliedTimeout)?; + let event = rpc::query_tx_status::<_, IO>( + client, + decrypted_query, + deadline, + ) + .await + .proceed_or(Error::AppliedTimeout)?; let parsed = TxResponse::from_event(event); - println!( + display_line!( + IO, "Transaction applied with result: {}", serde_json::to_string_pretty(&parsed).unwrap() ); @@ -565,7 +589,7 @@ pub fn decode_component( } /// Save accounts initialized from a tx into the wallet, if any. -pub async fn save_initialized_accounts( +pub async fn save_initialized_accounts( wallet: &mut Wallet, args: &args::Tx, initialized_accounts: Vec
, @@ -573,7 +597,8 @@ pub async fn save_initialized_accounts( let len = initialized_accounts.len(); if len != 0 { // Store newly initialized account addresses in the wallet - println!( + display_line!( + IO, "The transaction initialized {} new account{}", len, if len == 1 { "" } else { "s" } @@ -604,12 +629,16 @@ pub async fn save_initialized_accounts( ); match added { Some(new_alias) if new_alias != encoded => { - println!( + display_line!( + IO, "Added alias {} for address {}.", - new_alias, encoded + new_alias, + encoded ); } - _ => println!("No alias added for address {}.", encoded), + _ => { + display_line!(IO, "No alias added for address {}.", encoded) + } }; } } @@ -619,6 +648,7 @@ pub async fn save_initialized_accounts( pub async fn build_validator_commission_change< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -626,10 +656,12 @@ pub async fn build_validator_commission_change< ) -> Result<(Tx, Option
, common::PublicKey), Error> { let epoch = rpc::query_epoch(client).await; - let tx_code_hash = - query_wasm_code_hash(client, args.tx_code_path.to_str().unwrap()) - .await - .unwrap(); + let tx_code_hash = query_wasm_code_hash::<_, IO>( + client, + args.tx_code_path.to_str().unwrap(), + ) + .await + .unwrap(); // TODO: put following two let statements in its own function let params_key = crate::ledger::pos::params_key(); @@ -640,7 +672,11 @@ pub async fn build_validator_commission_change< let validator = args.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); + edisplay!( + IO, + "Invalid new commission rate, received {}", + args.rate + ); return Err(Error::InvalidCommissionRate(args.rate)); } @@ -660,7 +696,8 @@ pub async fn build_validator_commission_change< if args.rate.abs_diff(&commission_rate) > max_commission_change_per_epoch { - eprintln!( + edisplay!( + IO, "New rate is too large of a change with respect to \ the predecessor epoch in which the rate will take \ effect." @@ -671,14 +708,14 @@ pub async fn build_validator_commission_change< } } None => { - eprintln!("Error retrieving from storage"); + edisplay!(IO, "Error retrieving from storage"); if !args.tx.force { return Err(Error::Retrieval); } } } } else { - eprintln!("The given address {validator} is not a validator."); + edisplay!(IO, "The given address {validator} is not a validator."); if !args.tx.force { return Err(Error::InvalidValidatorAddress(validator)); } @@ -697,7 +734,7 @@ pub async fn build_validator_commission_change< tx.set_code(Code::from_hash(tx_code_hash)); let default_signer = args.validator.clone(); - prepare_tx::( + prepare_tx::( client, wallet, &args.tx, @@ -713,21 +750,27 @@ pub async fn build_validator_commission_change< pub async fn build_unjail_validator< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, args: args::TxUnjailValidator, ) -> Result<(Tx, Option
, common::PublicKey), Error> { if !rpc::is_validator(client, &args.validator).await { - eprintln!("The given address {} is not a validator.", &args.validator); + edisplay!( + IO, + "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 tx_code_hash = query_wasm_code_hash::<_, IO>(client, tx_code_path) + .await + .unwrap(); let data = args .validator @@ -742,7 +785,7 @@ pub async fn build_unjail_validator< tx.set_code(Code::from_hash(tx_code_hash)); let default_signer = args.validator; - prepare_tx( + prepare_tx::<_, _, IO>( client, wallet, &args.tx, @@ -758,21 +801,27 @@ pub async fn build_unjail_validator< pub async fn submit_unjail_validator< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( 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); + edisplay!( + IO, + "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 tx_code_hash = query_wasm_code_hash::<_, IO>(client, tx_code_path) + .await + .unwrap(); let data = args .validator @@ -787,7 +836,7 @@ pub async fn submit_unjail_validator< tx.set_code(Code::from_hash(tx_code_hash)); let default_signer = args.validator; - prepare_tx( + prepare_tx::<_, _, IO>( client, wallet, &args.tx, @@ -804,6 +853,7 @@ pub async fn submit_unjail_validator< pub async fn build_withdraw< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -811,16 +861,21 @@ pub async fn build_withdraw< ) -> Result<(Tx, Option
, common::PublicKey), Error> { let epoch = rpc::query_epoch(client).await; - let validator = - known_validator_or_err(args.validator.clone(), args.tx.force, client) - .await?; + let validator = known_validator_or_err::<_, IO>( + args.validator.clone(), + args.tx.force, + client, + ) + .await?; let source = args.source.clone(); - let tx_code_hash = - query_wasm_code_hash(client, args.tx_code_path.to_str().unwrap()) - .await - .unwrap(); + let tx_code_hash = query_wasm_code_hash::<_, IO>( + client, + args.tx_code_path.to_str().unwrap(), + ) + .await + .unwrap(); // Check the source's current unbond amount let bond_source = source.clone().unwrap_or_else(|| validator.clone()); @@ -832,21 +887,24 @@ pub async fn build_withdraw< ) .await; if tokens.is_zero() { - eprintln!( + edisplay!( + IO, "There are no unbonded bonds ready to withdraw in the current \ epoch {}.", epoch ); - rpc::query_and_print_unbonds(client, &bond_source, &validator).await; + rpc::query_and_print_unbonds::<_, IO>(client, &bond_source, &validator) + .await; if !args.tx.force { return Err(Error::NoUnbondReady(epoch)); } } else { - println!( + display_line!( + IO, "Found {} tokens that can be withdrawn.", tokens.to_string_native() ); - println!("Submitting transaction to withdraw them..."); + display_line!(IO, "Submitting transaction to withdraw them..."); } let data = pos::Withdraw { validator, source }; @@ -859,7 +917,7 @@ pub async fn build_withdraw< tx.set_code(Code::from_hash(tx_code_hash)); let default_signer = args.source.unwrap_or(args.validator); - prepare_tx::( + prepare_tx::( client, wallet, &args.tx, @@ -875,6 +933,7 @@ pub async fn build_withdraw< pub async fn build_unbond< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -892,24 +951,32 @@ pub async fn build_unbond< // Check the source's current bond amount let bond_source = source.clone().unwrap_or_else(|| args.validator.clone()); - let tx_code_hash = - query_wasm_code_hash(client, args.tx_code_path.to_str().unwrap()) - .await - .unwrap(); + let tx_code_hash = query_wasm_code_hash::<_, IO>( + client, + args.tx_code_path.to_str().unwrap(), + ) + .await + .unwrap(); if !args.tx.force { - known_validator_or_err(args.validator.clone(), args.tx.force, client) - .await?; + known_validator_or_err::<_, IO>( + args.validator.clone(), + args.tx.force, + client, + ) + .await?; let bond_amount = rpc::query_bond(client, &bond_source, &args.validator, None).await; - println!( + display_line!( + IO, "Bond amount available for unbonding: {} NAM", bond_amount.to_string_native() ); if args.amount > bond_amount { - eprintln!( + edisplay!( + IO, "The total bonds of the source {} is lower than the amount to \ be unbonded. Amount to unbond is {} and the total bonds is \ {}.", @@ -952,7 +1019,7 @@ pub async fn build_unbond< tx.set_code(Code::from_hash(tx_code_hash)); let default_signer = args.source.unwrap_or_else(|| args.validator.clone()); - let (tx, signer_addr, default_signer) = prepare_tx::( + let (tx, signer_addr, default_signer) = prepare_tx::( client, wallet, &args.tx, @@ -967,7 +1034,7 @@ pub async fn build_unbond< } /// Query the unbonds post-tx -pub async fn query_unbonds( +pub async fn query_unbonds( client: &C, args: args::Unbond, latest_withdrawal_pre: Option<(Epoch, token::Amount)>, @@ -994,7 +1061,8 @@ pub async fn query_unbonds( match latest_withdraw_epoch_post.cmp(&latest_withdraw_epoch_pre) { std::cmp::Ordering::Less => { if args.tx.force { - eprintln!( + edisplay!( + IO, "Unexpected behavior reading the unbonds data has \ occurred" ); @@ -1003,7 +1071,8 @@ pub async fn query_unbonds( } } std::cmp::Ordering::Equal => { - println!( + display_line!( + IO, "Amount {} withdrawable starting from epoch {}", (latest_withdraw_amount_post - latest_withdraw_amount_pre) .to_string_native(), @@ -1011,7 +1080,8 @@ pub async fn query_unbonds( ); } std::cmp::Ordering::Greater => { - println!( + display_line!( + IO, "Amount {} withdrawable starting from epoch {}", latest_withdraw_amount_post.to_string_native(), latest_withdraw_epoch_post, @@ -1019,7 +1089,8 @@ pub async fn query_unbonds( } } } else { - println!( + display_line!( + IO, "Amount {} withdrawable starting from epoch {}", latest_withdraw_amount_post.to_string_native(), latest_withdraw_epoch_post, @@ -1032,21 +1103,27 @@ pub async fn query_unbonds( pub async fn build_bond< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, args: args::Bond, ) -> Result<(Tx, Option
, common::PublicKey), Error> { - let validator = - known_validator_or_err(args.validator.clone(), args.tx.force, client) - .await?; + let validator = known_validator_or_err::<_, IO>( + args.validator.clone(), + args.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) - .await - .map(Some), + Some(source) => { + source_exists_or_err::<_, IO>(source, args.tx.force, client) + .await + .map(Some) + } None => Ok(source), }?; // Check bond's source (source for delegation or validator for self-bonds) @@ -1055,7 +1132,7 @@ pub async fn build_bond< let balance_key = token::balance_key(&args.native_token, bond_source); // TODO Should we state the same error message for the native token? - check_balance_too_low_err( + check_balance_too_low_err::<_, IO>( &args.native_token, bond_source, args.amount, @@ -1065,10 +1142,12 @@ pub async fn build_bond< ) .await?; - let tx_code_hash = - query_wasm_code_hash(client, args.tx_code_path.to_str().unwrap()) - .await - .unwrap(); + let tx_code_hash = query_wasm_code_hash::<_, IO>( + client, + args.tx_code_path.to_str().unwrap(), + ) + .await + .unwrap(); let bond = pos::Bond { validator, @@ -1084,7 +1163,7 @@ pub async fn build_bond< tx.set_code(Code::from_hash(tx_code_hash)); let default_signer = args.source.unwrap_or(args.validator); - prepare_tx::( + prepare_tx::( client, wallet, &args.tx, @@ -1130,18 +1209,23 @@ pub async fn is_safe_voting_window( pub async fn build_ibc_transfer< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, args: args::TxIbcTransfer, ) -> Result<(Tx, Option
, common::PublicKey), Error> { // 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::<_, IO>( + args.source.clone(), + args.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::<_, IO>(args.token, args.tx.force, client).await?; // Check source balance let (sub_prefix, balance_key) = match args.sub_prefix { @@ -1156,7 +1240,7 @@ pub async fn build_ibc_transfer< None => (None, token::balance_key(&token, &source)), }; - check_balance_too_low_err( + check_balance_too_low_err::<_, IO>( &token, &source, args.amount, @@ -1166,10 +1250,12 @@ pub async fn build_ibc_transfer< ) .await?; - let tx_code_hash = - query_wasm_code_hash(client, args.tx_code_path.to_str().unwrap()) - .await - .unwrap(); + let tx_code_hash = query_wasm_code_hash::<_, IO>( + client, + args.tx_code_path.to_str().unwrap(), + ) + .await + .unwrap(); let denom = match sub_prefix { // To parse IbcToken address, remove the address prefix @@ -1225,7 +1311,7 @@ pub async fn build_ibc_transfer< tx.set_data(Data::new(data)); tx.set_code(Code::from_hash(tx_code_hash)); - prepare_tx::( + prepare_tx::( client, wallet, &args.tx, @@ -1315,6 +1401,7 @@ pub async fn build_transfer< C: crate::ledger::queries::Client + Sync, V: WalletUtils, U: ShieldedUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -1327,11 +1414,13 @@ pub async fn build_transfer< let token = args.token.clone(); // Check that the source address exists on chain - source_exists_or_err(source.clone(), args.tx.force, client).await?; + source_exists_or_err::<_, IO>(source.clone(), args.tx.force, client) + .await?; // Check that the target address exists on chain - target_exists_or_err(target.clone(), args.tx.force, client).await?; + target_exists_or_err::<_, IO>(target.clone(), args.tx.force, client) + .await?; // Check that the token address exists on chain - token_exists_or_err(token.clone(), args.tx.force, client).await?; + token_exists_or_err::<_, IO>(token.clone(), args.tx.force, client).await?; // Check source balance let (sub_prefix, balance_key) = match &args.sub_prefix { Some(ref sub_prefix) => { @@ -1346,7 +1435,7 @@ pub async fn build_transfer< }; // validate the amount given - let validated_amount = validate_amount( + let validated_amount = validate_amount::<_, IO>( client, args.amount, &token, @@ -1355,7 +1444,7 @@ pub async fn build_transfer< ) .await .expect("expected to validate amount"); - let validate_fee = validate_amount( + let validate_fee = validate_amount::<_, IO>( client, args.tx.fee_amount, &args.tx.fee_token, @@ -1369,7 +1458,7 @@ pub async fn build_transfer< args.amount = InputAmount::Validated(validated_amount); args.tx.fee_amount = InputAmount::Validated(validate_fee); - check_balance_too_low_err::( + check_balance_too_low_err::( &token, &source, validated_amount.amount, @@ -1395,7 +1484,7 @@ pub async fn build_transfer< // If our chosen signer is the MASP sentinel key, then our shielded inputs // will need to cover the gas fees. let chosen_signer = - tx_signer::(client, wallet, &args.tx, default_signer.clone()) + tx_signer::(client, wallet, &args.tx, default_signer.clone()) .await? .1; let shielded_gas = masp_tx_key().ref_to() == chosen_signer; @@ -1408,14 +1497,16 @@ pub async fn build_transfer< #[cfg(not(feature = "mainnet"))] let is_source_faucet = rpc::is_faucet_account(client, &source).await; - let tx_code_hash = - query_wasm_code_hash(client, args.tx_code_path.to_str().unwrap()) - .await - .unwrap(); + let tx_code_hash = query_wasm_code_hash::<_, IO>( + client, + args.tx_code_path.to_str().unwrap(), + ) + .await + .unwrap(); // Construct the shielded part of the transaction, if any let stx_result = shielded - .gen_shielded_transfer(client, &args, shielded_gas) + .gen_shielded_transfer::<_, IO>(client, &args, shielded_gas) .await; let shielded_parts = match stx_result { @@ -1484,7 +1575,7 @@ pub async fn build_transfer< tx.set_code(Code::from_hash(tx_code_hash)); // Dry-run/broadcast/submit the transaction - let (tx, signer_addr, def_key) = prepare_tx::( + let (tx, signer_addr, def_key) = prepare_tx::( client, wallet, &args.tx, @@ -1507,6 +1598,7 @@ pub async fn build_transfer< pub async fn build_init_account< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -1514,15 +1606,19 @@ pub async fn build_init_account< ) -> Result<(Tx, Option
, common::PublicKey), Error> { let public_key = args.public_key; - let vp_code_hash = - query_wasm_code_hash(client, args.vp_code_path.to_str().unwrap()) - .await - .unwrap(); + let vp_code_hash = query_wasm_code_hash::<_, IO>( + client, + args.vp_code_path.to_str().unwrap(), + ) + .await + .unwrap(); - let tx_code_hash = - query_wasm_code_hash(client, args.tx_code_path.to_str().unwrap()) - .await - .unwrap(); + let tx_code_hash = query_wasm_code_hash::<_, IO>( + client, + args.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(); @@ -1537,7 +1633,7 @@ pub async fn build_init_account< tx.set_data(Data::new(data)); tx.set_code(Code::from_hash(tx_code_hash)); - prepare_tx::( + prepare_tx::( client, wallet, &args.tx, @@ -1553,6 +1649,7 @@ pub async fn build_init_account< pub async fn build_update_vp< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -1566,7 +1663,11 @@ pub async fn build_update_vp< let exists = rpc::known_address::(client, &addr).await; if !exists { if args.tx.force { - eprintln!("The address {} doesn't exist on chain.", addr); + edisplay!( + IO, + "The address {} doesn't exist on chain.", + addr + ); Ok(()) } else { Err(Error::LocationDoesNotExist(addr.clone())) @@ -1577,7 +1678,8 @@ pub async fn build_update_vp< } Address::Implicit(_) => { if args.tx.force { - eprintln!( + edisplay!( + IO, "A validity predicate of an implicit address cannot be \ directly updated. You can use an established address for \ this purpose." @@ -1589,7 +1691,8 @@ pub async fn build_update_vp< } Address::Internal(_) => { if args.tx.force { - eprintln!( + edisplay!( + IO, "A validity predicate of an internal address cannot be \ directly updated." ); @@ -1600,15 +1703,19 @@ pub async fn build_update_vp< } }?; - let vp_code_hash = - query_wasm_code_hash(client, args.vp_code_path.to_str().unwrap()) - .await - .unwrap(); + let vp_code_hash = query_wasm_code_hash::<_, IO>( + client, + args.vp_code_path.to_str().unwrap(), + ) + .await + .unwrap(); - let tx_code_hash = - query_wasm_code_hash(client, args.tx_code_path.to_str().unwrap()) - .await - .unwrap(); + let tx_code_hash = query_wasm_code_hash::<_, IO>( + client, + args.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(); @@ -1623,7 +1730,7 @@ pub async fn build_update_vp< tx.set_data(Data::new(data)); tx.set_code(Code::from_hash(tx_code_hash)); - prepare_tx::( + prepare_tx::( client, wallet, &args.tx, @@ -1639,6 +1746,7 @@ pub async fn build_update_vp< pub async fn build_custom< C: crate::ledger::queries::Client + Sync, U: WalletUtils, + IO: Io, >( client: &C, wallet: &mut Wallet, @@ -1650,7 +1758,7 @@ pub async fn build_custom< args.data_path.map(|data| tx.set_data(Data::new(data))); tx.set_code(Code::new(args.code_path)); - prepare_tx::( + prepare_tx::( client, wallet, &args.tx, @@ -1662,13 +1770,16 @@ pub async fn build_custom< .await } -async fn expect_dry_broadcast( +async fn expect_dry_broadcast< + C: crate::ledger::queries::Client + Sync, + IO: Io, +>( to_broadcast: TxBroadcastData, client: &C, ) -> Result { match to_broadcast { TxBroadcastData::DryRun(tx) => { - rpc::dry_run_tx(client, tx.to_bytes()).await; + rpc::dry_run_tx::<_, IO>(client, tx.to_bytes()).await; Ok(ProcessTxResponse::DryRun) } TxBroadcastData::Wrapper { @@ -1686,7 +1797,10 @@ fn lift_rpc_error(res: Result) -> Result { /// Returns the given validator if the given address is a validator, /// otherwise returns an error, force forces the address through even /// if it isn't a validator -async fn known_validator_or_err( +async fn known_validator_or_err< + C: crate::ledger::queries::Client + Sync, + IO: Io, +>( validator: Address, force: bool, client: &C, @@ -1695,7 +1809,8 @@ async fn known_validator_or_err( let is_validator = rpc::is_validator(client, &validator).await; if !is_validator { if force { - eprintln!( + edisplay!( + IO, "The address {} doesn't belong to any known validator account.", validator ); @@ -1711,7 +1826,7 @@ async fn known_validator_or_err( /// general pattern for checking if an address exists on the chain, or /// throwing an error if it's not forced. Takes a generic error /// message and the error type. -async fn address_exists_or_err( +async fn address_exists_or_err( addr: Address, force: bool, client: &C, @@ -1725,7 +1840,7 @@ where let addr_exists = rpc::known_address::(client, &addr).await; if !addr_exists { if force { - eprintln!("{}", message); + edisplay!(IO, "{}", message); Ok(addr) } else { Err(err(addr)) @@ -1738,14 +1853,17 @@ where /// Returns the given token if the given address exists on chain /// otherwise returns an error, force forces the address through even /// if it isn't on chain -pub async fn token_exists_or_err( +pub async fn token_exists_or_err< + C: crate::ledger::queries::Client + Sync, + IO: Io, +>( token: Address, force: bool, client: &C, ) -> Result { let message = format!("The token address {} doesn't exist on chain.", token); - address_exists_or_err( + address_exists_or_err::<_, _, IO>( token, force, client, @@ -1758,14 +1876,17 @@ pub async fn token_exists_or_err( /// Returns the given source address if the given address exists on chain /// otherwise returns an error, force forces the address through even /// if it isn't on chain -async fn source_exists_or_err( +async fn source_exists_or_err< + C: crate::ledger::queries::Client + Sync, + IO: Io, +>( token: Address, force: bool, client: &C, ) -> Result { let message = format!("The source address {} doesn't exist on chain.", token); - address_exists_or_err( + address_exists_or_err::<_, _, IO>( token, force, client, @@ -1778,14 +1899,17 @@ async fn source_exists_or_err( /// Returns the given target address if the given address exists on chain /// otherwise returns an error, force forces the address through even /// if it isn't on chain -async fn target_exists_or_err( +async fn target_exists_or_err< + C: crate::ledger::queries::Client + Sync, + IO: Io, +>( token: Address, force: bool, client: &C, ) -> Result { let message = format!("The target address {} doesn't exist on chain.", token); - address_exists_or_err( + address_exists_or_err::<_, _, IO>( token, force, client, @@ -1798,7 +1922,10 @@ async fn target_exists_or_err( /// checks the balance at the given address is enough to transfer the /// given amount, along with the balance even existing. force /// overrides this -async fn check_balance_too_low_err( +async fn check_balance_too_low_err< + C: crate::ledger::queries::Client + Sync, + IO: Io, +>( token: &Address, source: &Address, amount: token::Amount, @@ -1812,7 +1939,8 @@ async fn check_balance_too_low_err( Some(balance) => { if balance < amount { if force { - eprintln!( + edisplay!( + IO, "The balance of the source {} of token {} is lower \ than the amount to be transferred. Amount to \ transfer is {} and the balance is {}.", @@ -1836,9 +1964,11 @@ async fn check_balance_too_low_err( } None => { if force { - eprintln!( + edisplay!( + IO, "No balance found for the source {} of token {}", - source, token + source, + token ); Ok(()) } else { @@ -1849,13 +1979,17 @@ async fn check_balance_too_low_err( } #[allow(dead_code)] -fn validate_untrusted_code_err( +fn validate_untrusted_code_err( vp_code: &Vec, force: bool, ) -> Result<(), Error> { if let Err(err) = vm::validate_untrusted_wasm(vp_code) { if force { - eprintln!("Validity predicate code validation failed with {}", err); + edisplay!( + IO, + "Validity predicate code validation failed with {}", + err + ); Ok(()) } else { Err(Error::WasmValidationFailure(err)) diff --git a/shared/src/types/io.rs b/shared/src/types/io.rs new file mode 100644 index 0000000000..cf666f544c --- /dev/null +++ b/shared/src/types/io.rs @@ -0,0 +1,117 @@ +//! Traits for implementing IO handlers. This is to enable +//! generic IO. The defaults are the obvious Rust native +//! functions. + +/// Rust native I/O handling. +pub struct DefaultIo; + +impl Io for DefaultIo {} + +#[allow(missing_docs)] +pub trait Io { + fn print(output: impl AsRef) { + print!("{}", output.as_ref()); + } + + fn flush() { + use std::io::Write; + std::io::stdout().flush().unwrap(); + } + + fn println(output: impl AsRef) { + println!("{}", output.as_ref()); + } + + fn write( + mut writer: W, + output: impl AsRef, + ) -> std::io::Result<()> { + write!(writer, "{}", output.as_ref()) + } + + fn writeln( + mut writer: W, + output: impl AsRef, + ) -> std::io::Result<()> { + writeln!(writer, "{}", output.as_ref()) + } + + fn eprintln(output: impl AsRef) { + eprintln!("{}", output.as_ref()); + } + + fn read() -> std::io::Result { + read_aux(std::io::stdin().lock()) + } + + fn prompt(question: impl AsRef) -> String { + prompt_aux( + std::io::stdin().lock(), + std::io::stdout(), + question.as_ref(), + ) + } +} + +/// A generic function for displaying a prompt to users and reading +/// in their response. +pub fn prompt_aux(mut reader: R, mut writer: W, question: &str) -> String +where + R: std::io::Read, + W: std::io::Write, +{ + write!(&mut writer, "{}", question).expect("Unable to write"); + writer.flush().unwrap(); + let mut s = String::new(); + reader.read_to_string(&mut s).expect("Unable to read"); + s +} + +/// A generic function for reading input from users +pub fn read_aux(mut reader: R) -> std::io::Result +where + R: std::io::Read, +{ + let mut s = String::new(); + reader.read_to_string(&mut s)?; + Ok(s) +} + +/// Convenience macro for formatting arguments to +/// [`IO::print`] +#[macro_export] +macro_rules! display { + ($io:ty) => { + <$io>::print("") + }; + ($io:ty, $w:expr; $($args:tt)*) => { + <$io>::write($w, format_args!($($args)*).to_string()) + }; + ($io:ty,$($args:tt)*) => { + <$io>::print(format_args!($($args)*).to_string()) + }; +} + +/// Convenience macro for formatting arguments to +/// [`IO::println`] and [`IO::writeln`] +#[macro_export] +macro_rules! display_line { + ($io:ty) => { + <$io>::println("") + }; + ($io:ty, $w:expr; $($args:tt)*) => { + <$io>::writeln($w, format_args!($($args)*).to_string()) + }; + ($io:ty,$($args:tt)*) => { + <$io>::println(format_args!($($args)*).to_string()) + }; +} + +/// Convenience macro for formatting arguments to +/// [`IO::eprintln`] +#[macro_export] +macro_rules! edisplay { + ($io:ty,$($args:tt)*) => { + <$io>::eprintln(format_args!($($args)*).to_string()) + }; +} diff --git a/shared/src/types/mod.rs b/shared/src/types/mod.rs index 4f1a795d40..e0b51e5ef1 100644 --- a/shared/src/types/mod.rs +++ b/shared/src/types/mod.rs @@ -2,6 +2,7 @@ pub mod control_flow; pub mod ibc; +pub mod io; pub mod key; pub use namada_core::types::{ diff --git a/tests/src/e2e/ledger_tests.rs b/tests/src/e2e/ledger_tests.rs index ca7bd974c7..75ee8bfd44 100644 --- a/tests/src/e2e/ledger_tests.rs +++ b/tests/src/e2e/ledger_tests.rs @@ -21,6 +21,7 @@ use color_eyre::eyre::Result; use data_encoding::HEXLOWER; use namada::types::address::{btc, eth, masp_rewards, Address}; use namada::types::governance::ProposalType; +use namada::types::io::DefaultIo; use namada::types::storage::Epoch; use namada::types::token; use namada_apps::client::tx::CLIShieldedUtils; @@ -664,7 +665,7 @@ fn ledger_txs_and_queries() -> Result<()> { #[test] fn masp_txs_and_queries() -> Result<()> { // Download the shielded pool parameters before starting node - let _ = CLIShieldedUtils::new(PathBuf::new()); + let _ = CLIShieldedUtils::new::(PathBuf::new()); // Lengthen epoch to ensure that a transaction can be constructed and // submitted within the same block. Necessary to ensure that conversion is // not invalidated. @@ -927,7 +928,7 @@ fn masp_txs_and_queries() -> Result<()> { #[test] fn masp_pinned_txs() -> Result<()> { // Download the shielded pool parameters before starting node - let _ = CLIShieldedUtils::new(PathBuf::new()); + let _ = CLIShieldedUtils::new::(PathBuf::new()); // Lengthen epoch to ensure that a transaction can be constructed and // submitted within the same block. Necessary to ensure that conversion is // not invalidated. @@ -1107,7 +1108,7 @@ fn masp_incentives() -> Result<()> { // The number of decimal places used by ETH amounts. const ETH_DENOMINATION: u8 = 18; // Download the shielded pool parameters before starting node - let _ = CLIShieldedUtils::new(PathBuf::new()); + let _ = CLIShieldedUtils::new::(PathBuf::new()); // Lengthen epoch to ensure that a transaction can be constructed and // submitted within the same block. Necessary to ensure that conversion is // not invalidated. From 3c968bfd297c721b94eb6b9083d0b5d5e1b5e5d8 Mon Sep 17 00:00:00 2001 From: satan Date: Sat, 22 Jul 2023 00:42:46 +0200 Subject: [PATCH 2/9] [fix]: Fixed intra-doc link typo --- shared/src/types/io.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shared/src/types/io.rs b/shared/src/types/io.rs index cf666f544c..3f130887da 100644 --- a/shared/src/types/io.rs +++ b/shared/src/types/io.rs @@ -78,7 +78,7 @@ where } /// Convenience macro for formatting arguments to -/// [`IO::print`] +/// [`Io::print`] #[macro_export] macro_rules! display { ($io:ty) => { @@ -93,7 +93,7 @@ macro_rules! display { } /// Convenience macro for formatting arguments to -/// [`IO::println`] and [`IO::writeln`] +/// [`Io::println`] and [`Io::writeln`] #[macro_export] macro_rules! display_line { ($io:ty) => { @@ -108,7 +108,7 @@ macro_rules! display_line { } /// Convenience macro for formatting arguments to -/// [`IO::eprintln`] +/// [`Io::eprintln`] #[macro_export] macro_rules! edisplay { ($io:ty,$($args:tt)*) => { From c33d0e0dc6ff67eb9869d8e5a90f84b2e7049ec6 Mon Sep 17 00:00:00 2001 From: satan Date: Mon, 24 Jul 2023 17:36:34 +0200 Subject: [PATCH 3/9] [chore]: Added IO macros to wallet cli. Renamed to --- apps/src/lib/cli/wallet.rs | 182 +++++++++--------- apps/src/lib/client/rpc.rs | 56 ++++-- apps/src/lib/client/tx.rs | 63 +++--- shared/src/ledger/eth_bridge.rs | 9 +- shared/src/ledger/eth_bridge/validator_set.rs | 11 +- shared/src/ledger/masp.rs | 4 +- shared/src/ledger/rpc.rs | 14 +- shared/src/ledger/signing.rs | 4 +- shared/src/ledger/tx.rs | 40 ++-- shared/src/types/io.rs | 2 +- 10 files changed, 216 insertions(+), 169 deletions(-) diff --git a/apps/src/lib/cli/wallet.rs b/apps/src/lib/cli/wallet.rs index 56a0960db6..d72ee3ecd0 100644 --- a/apps/src/lib/cli/wallet.rs +++ b/apps/src/lib/cli/wallet.rs @@ -12,6 +12,7 @@ use namada::ledger::wallet::{DecryptionError, FindKeyError}; use namada::types::io::Io; use namada::types::key::*; use namada::types::masp::{MaspValue, PaymentAddress}; +use namada::{display, display_line, edisplay_line}; use rand_core::OsRng; use crate::cli; @@ -98,28 +99,29 @@ fn address_key_find( let alias = alias.to_lowercase(); if let Ok(viewing_key) = wallet.find_viewing_key(&alias) { // Check if alias is a viewing key - IO::println(format!("Viewing key: {}", viewing_key)); + display_line!(IO, "Viewing key: {}", viewing_key); if unsafe_show_secret { // Check if alias is also a spending key match wallet.find_spending_key(&alias, None) { Ok(spending_key) => { - IO::println(format!("Spending key: {}", spending_key)) + display_line!(IO, "Spending key: {}", spending_key) } Err(FindKeyError::KeyNotFound) => {} - Err(err) => IO::eprintln(format!("{}", err)), + Err(err) => edisplay_line!(IO, "{}", err), } } } else if let Some(payment_addr) = wallet.find_payment_addr(&alias) { // Failing that, check if alias is a payment address - IO::println(format!("Payment address: {}", payment_addr)); + display_line!(IO, "Payment address: {}", payment_addr); } else { // Otherwise alias cannot be referring to any shielded value - IO::println(format!( + display_line!( + IO, "No shielded address or key with alias {} found. Use the commands \ `masp list-addrs` and `masp list-keys` to see all the known \ addresses and keys.", alias.to_lowercase() - )); + ); } } @@ -135,32 +137,33 @@ fn spending_keys_list( let known_view_keys = wallet.get_viewing_keys(); let known_spend_keys = wallet.get_spending_keys(); if known_view_keys.is_empty() { - IO::println( + display_line!( + IO, "No known keys. Try `masp add --alias my-addr --value ...` to add \ a new key to the wallet.", ); } else { let stdout = io::stdout(); let mut w = stdout.lock(); - IO::writeln(&mut w, "Known keys:").unwrap(); + display_line!(IO, &mut w; "Known keys:").unwrap(); for (alias, key) in known_view_keys { - IO::write(&mut w, format!(" Alias \"{}\"", alias)).unwrap(); + display!(IO, &mut w; " Alias \"{}\"", alias).unwrap(); let spending_key_opt = known_spend_keys.get(&alias); // If this alias is associated with a spending key, indicate whether // or not the spending key is encrypted // TODO: consider turning if let into match if let Some(spending_key) = spending_key_opt { if spending_key.is_encrypted() { - IO::writeln(&mut w, " (encrypted):") + display_line!(IO, &mut w; " (encrypted):") } else { - IO::writeln(&mut w, " (not encrypted):") + display_line!(IO, &mut w; " (not encrypted):") } .unwrap(); } else { - IO::writeln(&mut w, ":").unwrap(); + display_line!(IO, &mut w; ":").unwrap(); } // Always print the corresponding viewing key - IO::writeln(&mut w, format!(" Viewing Key: {}", key)).unwrap(); + display_line!(IO, &mut w; " Viewing Key: {}", key).unwrap(); // A subset of viewing keys will have corresponding spending keys. // Print those too if they are available and requested. if unsafe_show_secret { @@ -169,9 +172,9 @@ fn spending_keys_list( // Here the spending key is unencrypted or successfully // decrypted Ok(spending_key) => { - IO::writeln( - &mut w, - format!(" Spending key: {}", spending_key), + display_line!(IO, + &mut w; + " Spending key: {}", spending_key, ) .unwrap(); } @@ -183,12 +186,10 @@ fn spending_keys_list( // Here the key is encrypted but incorrect password has // been provided Err(err) => { - IO::writeln( - &mut w, - format!( + display_line!(IO, + &mut w; " Couldn't decrypt the spending key: {}", - err - ), + err, ) .unwrap(); } @@ -204,17 +205,17 @@ fn payment_addresses_list(ctx: Context) { let wallet = ctx.wallet; let known_addresses = wallet.get_payment_addrs(); if known_addresses.is_empty() { - IO::println( + display_line!( + IO, "No known payment addresses. Try `masp gen-addr --alias my-addr` \ to generate a new payment address.", ); } else { let stdout = io::stdout(); let mut w = stdout.lock(); - IO::writeln(&mut w, "Known payment addresses:").unwrap(); + display_line!(IO, &mut w; "Known payment addresses:").unwrap(); for (alias, address) in sorted(known_addresses) { - IO::writeln(&mut w, format!(" \"{}\": {}", alias, address)) - .unwrap(); + display_line!(IO, &mut w; " \"{}\": {}", alias, address).unwrap(); } } } @@ -233,10 +234,11 @@ fn spending_key_gen( let password = read_and_confirm_encryption_password(unsafe_dont_encrypt); let (alias, _key) = wallet.gen_spending_key(alias, password, alias_force); crate::wallet::save(&wallet).unwrap_or_else(|err| eprintln!("{}", err)); - IO::println(format!( + display_line!( + IO, "Successfully added a spending key with alias: \"{}\"", alias - )); + ); } /// Generate a shielded payment address from the given key. @@ -263,14 +265,15 @@ fn payment_address_gen( alias_force, ) .unwrap_or_else(|| { - IO::eprintln("Payment address not added"); + edisplay_line!(IO, "Payment address not added"); cli::safe_exit(1); }); crate::wallet::save(&wallet).unwrap_or_else(|err| eprintln!("{}", err)); - IO::println(format!( + display_line!( + IO, "Successfully generated a payment address with the following alias: {}", alias, - )); + ); } /// Add a viewing key, spending key, or payment address to wallet. @@ -290,7 +293,7 @@ fn address_key_add( .wallet .insert_viewing_key(alias, viewing_key, alias_force) .unwrap_or_else(|| { - IO::eprintln("Viewing key not added"); + edisplay_line!(IO, "Viewing key not added"); cli::safe_exit(1); }); (alias, "viewing key") @@ -307,7 +310,7 @@ fn address_key_add( alias_force, ) .unwrap_or_else(|| { - IO::eprintln("Spending key not added"); + edisplay_line!(IO, "Spending key not added"); cli::safe_exit(1); }); (alias, "spending key") @@ -317,17 +320,19 @@ fn address_key_add( .wallet .insert_payment_addr(alias, payment_addr, alias_force) .unwrap_or_else(|| { - IO::eprintln("Payment address not added"); + edisplay_line!(IO, "Payment address not added"); cli::safe_exit(1); }); (alias, "payment address") } }; crate::wallet::save(&ctx.wallet).unwrap_or_else(|err| eprintln!("{}", err)); - IO::println(format!( + display_line!( + IO, "Successfully added a {} with the following alias to wallet: {}", - typ, alias, - )); + typ, + alias, + ); } /// Restore a keypair and an implicit address from the mnemonic code in the @@ -354,19 +359,20 @@ fn key_and_address_restore( encryption_password, ) .unwrap_or_else(|err| { - IO::eprintln(format!("{}", err)); + edisplay_line!(IO, "{}", err); cli::safe_exit(1) }) .unwrap_or_else(|| { - IO::println("No changes are persisted. Exiting."); + display_line!(IO, "No changes are persisted. Exiting."); cli::safe_exit(0); }); crate::wallet::save(&wallet) - .unwrap_or_else(|err| IO::eprintln(format!("{}", err))); - IO::println(format!( + .unwrap_or_else(|err| edisplay_line!(IO, "{}", err)); + display_line!( + IO, "Successfully added a key and an address with alias: \"{}\"", alias - )); + ); } /// Generate a new keypair and derive implicit address from it and store them in @@ -396,19 +402,20 @@ fn key_and_address_gen( derivation_path_and_mnemonic_rng, ) .unwrap_or_else(|err| { - IO::eprintln(format!("{}", err)); + edisplay_line!(IO, "{}", err); cli::safe_exit(1); }) .unwrap_or_else(|| { - IO::println("No changes are persisted. Exiting."); + display_line!(IO, "No changes are persisted. Exiting."); cli::safe_exit(0); }); crate::wallet::save(&wallet) - .unwrap_or_else(|err| IO::eprintln(format!("{}", err))); - IO::println(format!( + .unwrap_or_else(|err| edisplay_line!(IO, "{}", err)); + display_line!( + IO, "Successfully added a key and an address with alias: \"{}\"", alias - )); + ); } /// Find a keypair in the wallet store. @@ -428,7 +435,8 @@ fn key_find( let alias = alias.or(value); match alias { None => { - IO::eprintln( + edisplay_line!( + IO, "An alias, public key or public key hash needs to be \ supplied", ); @@ -441,14 +449,14 @@ fn key_find( match found_keypair { Ok(keypair) => { let pkh: PublicKeyHash = (&keypair.ref_to()).into(); - IO::println(format!("Public key hash: {}", pkh)); - IO::println(format!("Public key: {}", keypair.ref_to())); + display_line!(IO, "Public key hash: {}", pkh); + display_line!(IO, "Public key: {}", keypair.ref_to()); if unsafe_show_secret { - IO::println(format!("Secret key: {}", keypair)); + display_line!(IO, "Secret key: {}", keypair); } } Err(err) => { - IO::eprintln(format!("{}", err)); + edisplay_line!(IO, "{}", err); } } } @@ -464,40 +472,41 @@ fn key_list( let wallet = ctx.wallet; let known_keys = wallet.get_keys(); if known_keys.is_empty() { - IO::println( + display_line!( + IO, "No known keys. Try `key gen --alias my-key` to generate a new \ key.", ); } else { let stdout = io::stdout(); let mut w = stdout.lock(); - IO::writeln(&mut w, "Known keys:").unwrap(); + display_line!(IO, &mut w; "Known keys:").unwrap(); for (alias, (stored_keypair, pkh)) in known_keys { let encrypted = if stored_keypair.is_encrypted() { "encrypted" } else { "not encrypted" }; - IO::writeln( - &mut w, - format!(" Alias \"{}\" ({}):", alias, encrypted), + display_line!(IO, + &mut w; + " Alias \"{}\" ({}):", alias, encrypted, ) .unwrap(); if let Some(pkh) = pkh { - IO::writeln(&mut w, format!(" Public key hash: {}", pkh)) + display_line!(IO, &mut w; " Public key hash: {}", pkh) .unwrap(); } match stored_keypair.get::(decrypt, None) { Ok(keypair) => { - IO::writeln( - &mut w, - format!(" Public key: {}", keypair.ref_to()), + display_line!(IO, + &mut w; + " Public key: {}", keypair.ref_to(), ) .unwrap(); if unsafe_show_secret { - IO::writeln( - &mut w, - format!(" Secret key: {}", keypair), + display_line!(IO, + &mut w; + " Secret key: {}", keypair, ) .unwrap(); } @@ -506,9 +515,9 @@ fn key_list( continue; } Err(err) => { - IO::writeln( - &mut w, - format!(" Couldn't decrypt the keypair: {}", err), + display_line!(IO, + &mut w; + " Couldn't decrypt the keypair: {}", err, ) .unwrap(); } @@ -533,10 +542,10 @@ fn key_export( let mut file = File::create(&file_name).unwrap(); file.write_all(file_data.as_ref()).unwrap(); - IO::println(format!("Exported to file {}", file_name)); + display_line!(IO, "Exported to file {}", file_name); }) .unwrap_or_else(|err| { - IO::eprintln(format!("{}", err)); + edisplay_line!(IO, "{}", err); cli::safe_exit(1) }) } @@ -546,18 +555,19 @@ fn address_list(ctx: Context) { let wallet = ctx.wallet; let known_addresses = wallet.get_addresses(); if known_addresses.is_empty() { - IO::println( + display_line!( + IO, "No known addresses. Try `address gen --alias my-addr` to \ generate a new implicit address.", ); } else { let stdout = io::stdout(); let mut w = stdout.lock(); - IO::writeln(&mut w, "Known addresses:").unwrap(); + display_line!(IO, &mut w; "Known addresses:").unwrap(); for (alias, address) in sorted(known_addresses) { - IO::writeln( - &mut w, - format!(" \"{}\": {}", alias, address.to_pretty_string()), + display_line!(IO, + &mut w; + " \"{}\": {}", alias, address.to_pretty_string(), ) .unwrap(); } @@ -575,26 +585,25 @@ fn address_or_alias_find(ctx: Context, args: args::AddressOrAliasFind) { } else if args.alias.is_some() { if let Some(address) = wallet.find_address(args.alias.as_ref().unwrap()) { - IO::println(format!( - "Found address {}", - address.to_pretty_string() - )); + display_line!(IO, "Found address {}", address.to_pretty_string()); } else { - IO::println(format!( + display_line!( + IO, "No address with alias {} found. Use the command `address \ list` to see all the known addresses.", args.alias.unwrap().to_lowercase() - )); + ); } } else if args.address.is_some() { if let Some(alias) = wallet.find_alias(args.address.as_ref().unwrap()) { - IO::println(format!("Found alias {}", alias)); + display_line!(IO, "Found alias {}", alias); } else { - IO::println(format!( + display_line!( + IO, "No alias with address {} found. Use the command `address \ list` to see all the known addresses.", args.address.unwrap() - )); + ); } } } @@ -610,13 +619,14 @@ fn address_add(ctx: Context, args: args::AddressAdd) { ) .is_none() { - IO::eprintln("Address not added"); + edisplay_line!(IO, "Address not added"); cli::safe_exit(1); } crate::wallet::save(&wallet) - .unwrap_or_else(|err| IO::eprintln(format!("{}", err))); - IO::println(format!( + .unwrap_or_else(|err| edisplay_line!(IO, "{}", err)); + display_line!( + IO, "Successfully added a key and an address with alias: \"{}\"", args.alias.to_lowercase() - )); + ); } diff --git a/apps/src/lib/client/rpc.rs b/apps/src/lib/client/rpc.rs index 7ab2c3a03a..56696fb022 100644 --- a/apps/src/lib/client/rpc.rs +++ b/apps/src/lib/client/rpc.rs @@ -48,7 +48,7 @@ use namada::types::masp::{BalanceOwner, ExtendedViewingKey, PaymentAddress}; use namada::types::storage::{BlockHeight, BlockResults, Epoch, Key, KeySeg}; use namada::types::token::{Change, MaspDenom}; use namada::types::{storage, token}; -use namada::{display, display_line, edisplay}; +use namada::{display, display_line, edisplay_line}; use tokio::time::Instant; use crate::cli::{self, args}; @@ -460,7 +460,7 @@ pub async fn query_pinned_balance< let fvk = match ExtendedViewingKey::from_str(vk_str.trim()) { Ok(fvk) => fvk, _ => { - edisplay!(IO, "Invalid viewing key entered"); + edisplay_line!(IO, "Invalid viewing key entered"); continue; } }; @@ -724,7 +724,11 @@ pub async fn query_proposal< display_line!(IO, "{:4}Status: on-going", ""); } Err(msg) => { - edisplay!(IO, "Error in tally computation: {}", msg); + edisplay_line!( + IO, + "Error in tally computation: {}", + msg + ); } } } else { @@ -739,7 +743,11 @@ pub async fn query_proposal< ); } Err(msg) => { - edisplay!(IO, "Error in tally computation: {}", msg); + edisplay_line!( + IO, + "Error in tally computation: {}", + msg + ); } } } @@ -769,7 +777,11 @@ pub async fn query_proposal< .await .is_none() { - edisplay!(IO, "No valid proposal was found with id {}", id); + edisplay_line!( + IO, + "No valid proposal was found with id {}", + id + ); } } None => { @@ -784,7 +796,11 @@ pub async fn query_proposal< .await .is_none() { - edisplay!(IO, "No valid proposal was found with id {}", id); + edisplay_line!( + IO, + "No valid proposal was found with id {}", + id + ); }; } } @@ -1148,7 +1164,7 @@ pub async fn query_proposal_result< ); } Err(msg) => { - edisplay!( + edisplay_line!( IO, "Error in tally computation: {}", msg @@ -1156,12 +1172,12 @@ pub async fn query_proposal_result< } } } else { - edisplay!(IO, "Proposal is still in progress."); + edisplay_line!(IO, "Proposal is still in progress."); cli::safe_exit(1) } } None => { - edisplay!(IO, "Error while retriving proposal."); + edisplay_line!(IO, "Error while retriving proposal."); cli::safe_exit(1) } } @@ -1199,7 +1215,7 @@ pub async fn query_proposal_result< } } Err(e) => { - edisplay!( + edisplay_line!( IO, "Can't read entry type: {}.", e @@ -1208,14 +1224,18 @@ pub async fn query_proposal_result< } }, Err(e) => { - edisplay!(IO, "Can't read entry: {}.", e); + edisplay_line!( + IO, + "Can't read entry: {}.", + e + ); cli::safe_exit(1) } } } if !is_proposal_present { - edisplay!( + edisplay_line!( IO, "The folder must contain the offline proposal \ in a file named \"proposal\"" @@ -1236,7 +1256,7 @@ pub async fn query_proposal_result< .expect("Public key should exist."); if !proposal.check_signature(&public_key) { - edisplay!(IO, "Bad proposal signature."); + edisplay_line!(IO, "Bad proposal signature."); cli::safe_exit(1) } @@ -1267,7 +1287,7 @@ pub async fn query_proposal_result< ); } Err(msg) => { - edisplay!( + edisplay_line!( IO, "Error in tally computation: {}", msg @@ -1276,7 +1296,7 @@ pub async fn query_proposal_result< } } None => { - edisplay!( + edisplay_line!( IO, "Offline flag must be followed by data-path." ); @@ -1284,7 +1304,7 @@ pub async fn query_proposal_result< } }; } else { - edisplay!( + edisplay_line!( IO, "Either --proposal-id or --data-path should be provided \ as arguments." @@ -1976,7 +1996,7 @@ pub async fn query_find_validator< ) { let args::QueryFindValidator { query: _, tm_addr } = args; if tm_addr.len() != 40 { - edisplay!( + edisplay_line!( IO, "Expected 40 characters in Tendermint address, got {}", tm_addr.len() @@ -2259,7 +2279,7 @@ pub async fn query_result( ), Err(err2) => { // Print the errors that caused the lookups to fail - edisplay!(IO, "{}\n{}", err1, err2); + edisplay_line!(IO, "{}\n{}", err1, err2); cli::safe_exit(1) } } diff --git a/apps/src/lib/client/tx.rs b/apps/src/lib/client/tx.rs index c3c802ced1..1d6144454c 100644 --- a/apps/src/lib/client/tx.rs +++ b/apps/src/lib/client/tx.rs @@ -28,7 +28,7 @@ use namada::types::storage::{Epoch, Key}; use namada::types::token; use namada::types::transaction::governance::{ProposalType, VoteProposalData}; use namada::types::transaction::{InitValidator, TxType}; -use namada::{display_line, edisplay}; +use namada::{display_line, edisplay_line}; use super::rpc; use crate::cli::context::WalletAddress; @@ -223,7 +223,7 @@ where .map(|key| match key { common::SecretKey::Ed25519(_) => key, common::SecretKey::Secp256k1(_) => { - edisplay!(IO, "Consensus key can only be ed25519"); + edisplay_line!(IO, "Consensus key can only be ed25519"); safe_exit(1) } }) @@ -249,7 +249,7 @@ where .map(|key| match key { common::SecretKey::Secp256k1(_) => key.ref_to(), common::SecretKey::Ed25519(_) => { - edisplay!(IO, "Eth cold key can only be secp256k1"); + edisplay_line!(IO, "Eth cold key can only be secp256k1"); safe_exit(1) } }) @@ -276,7 +276,7 @@ where .map(|key| match key { common::SecretKey::Secp256k1(_) => key.ref_to(), common::SecretKey::Ed25519(_) => { - edisplay!(IO, "Eth hot key can only be secp256k1"); + edisplay_line!(IO, "Eth hot key can only be secp256k1"); safe_exit(1) } }) @@ -326,7 +326,7 @@ where // Validate the commission rate data if commission_rate > Dec::one() || commission_rate < Dec::zero() { - edisplay!( + edisplay_line!( IO, "The validator commission rate must not exceed 1.0 or 100%, and \ it must be 0 or positive" @@ -338,7 +338,7 @@ where if max_commission_rate_change > Dec::one() || max_commission_rate_change < Dec::zero() { - edisplay!( + edisplay_line!( IO, "The validator maximum change in commission rate per epoch must \ not exceed 1.0 or 100%" @@ -407,12 +407,12 @@ where if let Some(alias) = ctx.wallet.find_alias(validator_address) { (alias.clone(), validator_address.clone()) } else { - edisplay!(IO, "Expected one account to be created"); + edisplay_line!(IO, "Expected one account to be created"); safe_exit(1) } } _ => { - edisplay!(IO, "Expected one account to be created"); + edisplay_line!(IO, "Expected one account to be created"); safe_exit(1) } }; @@ -420,7 +420,7 @@ where ctx.wallet .add_validator_data(validator_address, validator_keys); crate::wallet::save(&ctx.wallet) - .unwrap_or_else(|err| edisplay!(IO, "{}", err)); + .unwrap_or_else(|err| edisplay_line!(IO, "{}", err)); let tendermint_home = ctx.config.ledger.cometbft_dir(); tendermint_node::write_validator_key(&tendermint_home, &consensus_key); @@ -628,7 +628,7 @@ pub async fn submit_transfer( tx_epoch.unwrap() != submission_epoch => { // Then we probably straddled an epoch boundary. Let's retry... - edisplay!(IO, + edisplay_line!(IO, "MASP transaction rejected and this may be due to the \ epoch changing. Attempting to resubmit transaction.", ); @@ -701,7 +701,7 @@ where % governance_parameters.min_proposal_period == 0 ); - edisplay!( + edisplay_line!( IO, "Invalid proposal start epoch: {} must be greater than current \ epoch {} and a multiple of {}", @@ -719,7 +719,7 @@ where > governance_parameters.max_proposal_period || proposal.voting_end_epoch.0 % 3 != 0 { - edisplay!( + edisplay_line!( IO, "Invalid proposal end epoch: difference between proposal start \ and end epoch must be at least {} and at max {} and end epoch \ @@ -735,7 +735,7 @@ where || proposal.grace_epoch.0 - proposal.voting_end_epoch.0 < governance_parameters.min_proposal_grace_epochs { - edisplay!( + edisplay_line!( IO, "Invalid proposal grace epoch: difference between proposal grace \ and end epoch must be at least {}", @@ -768,7 +768,11 @@ where ); } Err(e) => { - edisplay!(IO, "Error while creating proposal file: {}.", e); + edisplay_line!( + IO, + "Error while creating proposal file: {}.", + e + ); safe_exit(1) } } @@ -780,7 +784,10 @@ where if let Ok(data) = tx_data { data } else { - edisplay!(IO, "Invalid data for init proposal transaction."); + edisplay_line!( + IO, + "Invalid data for init proposal transaction." + ); safe_exit(1) }; @@ -794,7 +801,7 @@ where ) .unwrap() { - edisplay!( + edisplay_line!( IO, "Address {} doesn't have enough funds.", &proposal.author @@ -805,7 +812,7 @@ where if init_proposal_content.len() > governance_parameters.max_proposal_content_size as usize { - edisplay!(IO, "Proposal content size too big."); + edisplay_line!(IO, "Proposal content size too big."); safe_exit(1); } @@ -876,7 +883,7 @@ where let signer = if let Some(addr) = &args.tx.signer { addr } else { - edisplay!(IO, "Missing mandatory argument --signer."); + edisplay_line!(IO, "Missing mandatory argument --signer."); safe_exit(1) }; @@ -916,7 +923,7 @@ where let msg = splits.next().expect("Missing message to sign"); if splits.next().is_some() { - edisplay!(IO, "Unexpected argument after message"); + edisplay_line!(IO, "Unexpected argument after message"); safe_exit(1); } @@ -932,14 +939,14 @@ where } "nay" => ProposalVote::Nay, _ => { - edisplay!(IO, "Vote must be either yay or nay"); + edisplay_line!(IO, "Vote must be either yay or nay"); safe_exit(1); } }; if args.offline { if !proposal_vote.is_default_vote() { - edisplay!( + edisplay_line!( IO, "Wrong vote type for offline proposal. Just vote yay or nay!" ); @@ -955,7 +962,7 @@ where .await .expect("Public key should exist."); if !proposal.check_signature(&public_key) { - edisplay!(IO, "Proposal signature mismatch!"); + edisplay_line!(IO, "Proposal signature mismatch!"); safe_exit(1) } @@ -984,7 +991,7 @@ where Ok(()) } Err(e) => { - edisplay!( + edisplay_line!( IO, "Error while creating proposal vote file: {}.", e @@ -1018,7 +1025,7 @@ where if let ProposalVote::Yay(ref vote_type) = proposal_vote { if &proposal_type != vote_type { - edisplay!( + edisplay_line!( IO, "Expected vote of type {}, found {}", proposal_type, @@ -1035,7 +1042,7 @@ where if !rpc::query_has_storage_key::(client, &vp_key) .await { - edisplay!( + edisplay_line!( IO, "Proposed PGF council {} cannot be found \ in storage", @@ -1045,7 +1052,7 @@ where } } _ => { - edisplay!( + edisplay_line!( IO, "PGF council vote contains a non-established \ address: {}", @@ -1061,7 +1068,7 @@ where match proposal_start_epoch { Some(epoch) => { if current_epoch < epoch { - edisplay!( + edisplay_line!( IO, "Current epoch {} is not greater than proposal start \ epoch {}", @@ -1151,7 +1158,7 @@ where Ok(()) } None => { - edisplay!( + edisplay_line!( IO, "Proposal start epoch for proposal id {} is not definied.", proposal_id diff --git a/shared/src/ledger/eth_bridge.rs b/shared/src/ledger/eth_bridge.rs index e5b10f20db..a73f5efd77 100644 --- a/shared/src/ledger/eth_bridge.rs +++ b/shared/src/ledger/eth_bridge.rs @@ -18,7 +18,7 @@ use crate::types::control_flow::time::{ }; use crate::types::control_flow::{self, Halt, TryHalt}; use crate::types::io::Io; -use crate::{display_line, edisplay}; +use crate::{display_line, edisplay_line}; const DEFAULT_BACKOFF: Duration = std::time::Duration::from_millis(500); const DEFAULT_CEILING: Duration = std::time::Duration::from_secs(30); @@ -127,7 +127,10 @@ where }) .await .try_halt(|_| { - edisplay!(IO, "Timed out while waiting for Ethereum to synchronize"); + edisplay_line!( + IO, + "Timed out while waiting for Ethereum to synchronize" + ); })?; display_line!(IO, "The Ethereum node is up to date"); control_flow::proceed(()) @@ -147,7 +150,7 @@ where .await .map(|status| status.is_synchronized()) .try_halt(|err| { - edisplay!( + edisplay_line!( IO, "An error occurred while fetching the Ethereum \ synchronization status: {err}" diff --git a/shared/src/ledger/eth_bridge/validator_set.rs b/shared/src/ledger/eth_bridge/validator_set.rs index d4c01f1c1a..fab665e711 100644 --- a/shared/src/ledger/eth_bridge/validator_set.rs +++ b/shared/src/ledger/eth_bridge/validator_set.rs @@ -25,7 +25,7 @@ use crate::types::control_flow::{ self, install_shutdown_signal, Halt, TryHalt, }; use crate::types::io::{DefaultIo, Io}; -use crate::{display_line, edisplay}; +use crate::{display_line, edisplay_line}; /// Relayer related errors. #[derive(Debug, Default)] @@ -345,7 +345,10 @@ where nam_client, |relay_result| match relay_result { RelayResult::GovernanceCallError(reason) => { - edisplay!(IO, "Calling Governance failed due to: {reason}"); + edisplay_line!( + IO, + "Calling Governance failed due to: {reason}" + ); } RelayResult::NonceError { argument, contract } => { let whence = match argument.cmp(&contract) { @@ -353,14 +356,14 @@ where Ordering::Equal => "identical to", Ordering::Greater => "too far ahead of", }; - edisplay!( + edisplay_line!( IO, "Argument nonce <{argument}> is {whence} contract \ nonce <{contract}>" ); } RelayResult::NoReceipt => { - edisplay!( + edisplay_line!( IO, "No transfer receipt received from the Ethereum node" ); diff --git a/shared/src/ledger/masp.rs b/shared/src/ledger/masp.rs index 9cc1a014f2..8596ceca84 100644 --- a/shared/src/ledger/masp.rs +++ b/shared/src/ledger/masp.rs @@ -75,7 +75,7 @@ use crate::types::token::{ Transfer, HEAD_TX_KEY, PIN_KEY_PREFIX, TX_KEY_PREFIX, }; use crate::types::transaction::{EllipticCurve, PairingEngine, WrapperTx}; -use crate::{display_line, edisplay}; +use crate::{display_line, edisplay_line}; /// Env var to point to a dir with MASP parameters. When not specified, /// the default OS specific path is used. @@ -1002,7 +1002,7 @@ impl ShieldedContext { make_asset_type(Some(asset_type.0), &asset_type.1, asset_type.2); let threshold = -conv[&masp_asset]; if threshold == 0 { - edisplay!( + edisplay_line!( IO, "Asset threshold of selected conversion for asset type {} is \ 0, this is a bug, please report it.", diff --git a/shared/src/ledger/rpc.rs b/shared/src/ledger/rpc.rs index 2937ba81f8..1bd42018c5 100644 --- a/shared/src/ledger/rpc.rs +++ b/shared/src/ledger/rpc.rs @@ -41,7 +41,7 @@ use crate::types::io::Io; use crate::types::key::*; use crate::types::storage::{BlockHeight, BlockResults, Epoch, PrefixValue}; use crate::types::{storage, token}; -use crate::{display_line, edisplay}; +use crate::{display_line, edisplay_line}; /// Query the status of a given transaction. /// @@ -88,7 +88,7 @@ where }) .await .try_halt(|_| { - edisplay!( + edisplay_line!( IO, "Transaction status query deadline of {deadline:?} exceeded" ); @@ -276,7 +276,7 @@ pub async fn query_wasm_code_hash< Some(Hash::try_from(&hash[..]).expect("Invalid code hash")) } None => { - edisplay!( + edisplay_line!( IO, "The corresponding wasm code of the code path {} doesn't \ exist on chain.", @@ -371,7 +371,7 @@ where &value[..], ) { Err(err) => { - edisplay!( + edisplay_line!( IO, "Skipping a value for key {}. Error in decoding: {}", key, @@ -1090,7 +1090,11 @@ where ControlFlow::Continue(()) } Err(e) => { - edisplay!(IO, "Failed to query node status with error: {}", e); + edisplay_line!( + IO, + "Failed to query node status with error: {}", + e + ); ControlFlow::Break(Err(())) } } diff --git a/shared/src/ledger/signing.rs b/shared/src/ledger/signing.rs index 56ae841d28..31e2256c3a 100644 --- a/shared/src/ledger/signing.rs +++ b/shared/src/ledger/signing.rs @@ -54,7 +54,7 @@ use crate::types::transaction::governance::{ use crate::types::transaction::{ Fee, InitAccount, InitValidator, TxType, UpdateVp, WrapperTx, }; -use crate::{display_line, edisplay}; +use crate::{display_line, edisplay_line}; #[cfg(feature = "std")] /// Env. var specifying where to store signing test vectors @@ -429,7 +429,7 @@ pub async fn sign_wrapper< format_denominated_amount::<_, IO>(client, &token_addr, balance) .await, ); - edisplay!(IO, "{}", err_msg); + edisplay_line!(IO, "{}", err_msg); if !args.force && cfg!(feature = "mainnet") { panic!("{}", err_msg); } diff --git a/shared/src/ledger/tx.rs b/shared/src/ledger/tx.rs index 79dda0363f..fabc4e6f40 100644 --- a/shared/src/ledger/tx.rs +++ b/shared/src/ledger/tx.rs @@ -52,7 +52,7 @@ use crate::types::time::DateTimeUtc; use crate::types::transaction::{pos, InitAccount, TxType, UpdateVp}; use crate::types::{storage, token}; use crate::vm::WasmValidationError; -use crate::{display_line, edisplay, vm}; +use crate::{display_line, edisplay_line, vm}; /// Initialize account transaction WASM pub const TX_INIT_ACCOUNT_WASM: &str = "tx_init_account.wasm"; @@ -682,7 +682,7 @@ pub async fn build_validator_commission_change< let validator = args.validator.clone(); if rpc::is_validator(client, &validator).await { if args.rate < Dec::zero() || args.rate > Dec::one() { - edisplay!( + edisplay_line!( IO, "Invalid new commission rate, received {}", args.rate @@ -706,7 +706,7 @@ pub async fn build_validator_commission_change< if args.rate.abs_diff(&commission_rate) > max_commission_change_per_epoch { - edisplay!( + edisplay_line!( IO, "New rate is too large of a change with respect to \ the predecessor epoch in which the rate will take \ @@ -718,14 +718,14 @@ pub async fn build_validator_commission_change< } } None => { - edisplay!(IO, "Error retrieving from storage"); + edisplay_line!(IO, "Error retrieving from storage"); if !args.tx.force { return Err(Error::Retrieval); } } } } else { - edisplay!(IO, "The given address {validator} is not a validator."); + edisplay_line!(IO, "The given address {validator} is not a validator."); if !args.tx.force { return Err(Error::InvalidValidatorAddress(validator)); } @@ -767,7 +767,7 @@ pub async fn build_unjail_validator< args: args::TxUnjailValidator, ) -> Result<(Tx, Option
, common::PublicKey), Error> { if !rpc::is_validator(client, &args.validator).await { - edisplay!( + edisplay_line!( IO, "The given address {} is not a validator.", &args.validator @@ -820,7 +820,7 @@ pub async fn submit_unjail_validator< args: args::TxUnjailValidator, ) -> Result<(), Error> { if !rpc::is_validator(client, &args.validator).await { - edisplay!( + edisplay_line!( IO, "The given address {} is not a validator.", &args.validator @@ -839,7 +839,7 @@ pub async fn submit_unjail_validator< .await .expect("Validator state should be defined."); if validator_state_at_pipeline != ValidatorState::Jailed { - edisplay!( + edisplay_line!( IO, "The given validator address {} is not jailed at the pipeline \ epoch when it would be restored to one of the validator sets.", @@ -861,7 +861,7 @@ pub async fn submit_unjail_validator< let eligible_epoch = last_slash_epoch + params.slash_processing_epoch_offset(); if current_epoch < eligible_epoch { - edisplay!( + edisplay_line!( IO, "The given validator address {} is currently frozen and not \ yet eligible to be unjailed.", @@ -946,7 +946,7 @@ pub async fn build_withdraw< ) .await; if tokens.is_zero() { - edisplay!( + edisplay_line!( IO, "There are no unbonded bonds ready to withdraw in the current \ epoch {}.", @@ -1034,7 +1034,7 @@ pub async fn build_unbond< ); if args.amount > bond_amount { - edisplay!( + edisplay_line!( IO, "The total bonds of the source {} is lower than the amount to \ be unbonded. Amount to unbond is {} and the total bonds is \ @@ -1120,7 +1120,7 @@ pub async fn query_unbonds( match latest_withdraw_epoch_post.cmp(&latest_withdraw_epoch_pre) { std::cmp::Ordering::Less => { if args.tx.force { - edisplay!( + edisplay_line!( IO, "Unexpected behavior reading the unbonds data has \ occurred" @@ -1689,7 +1689,7 @@ pub async fn build_update_vp< let exists = rpc::known_address::(client, &addr).await; if !exists { if args.tx.force { - edisplay!( + edisplay_line!( IO, "The address {} doesn't exist on chain.", addr @@ -1704,7 +1704,7 @@ pub async fn build_update_vp< } Address::Implicit(_) => { if args.tx.force { - edisplay!( + edisplay_line!( IO, "A validity predicate of an implicit address cannot be \ directly updated. You can use an established address for \ @@ -1717,7 +1717,7 @@ pub async fn build_update_vp< } Address::Internal(_) => { if args.tx.force { - edisplay!( + edisplay_line!( IO, "A validity predicate of an internal address cannot be \ directly updated." @@ -1835,7 +1835,7 @@ async fn known_validator_or_err< let is_validator = rpc::is_validator(client, &validator).await; if !is_validator { if force { - edisplay!( + edisplay_line!( IO, "The address {} doesn't belong to any known validator account.", validator @@ -1866,7 +1866,7 @@ where let addr_exists = rpc::known_address::(client, &addr).await; if !addr_exists { if force { - edisplay!(IO, "{}", message); + edisplay_line!(IO, "{}", message); Ok(addr) } else { Err(err(addr)) @@ -1942,7 +1942,7 @@ async fn check_balance_too_low_err< Some(balance) => { if balance < amount { if force { - edisplay!( + edisplay_line!( IO, "The balance of the source {} of token {} is lower \ than the amount to be transferred. Amount to \ @@ -1973,7 +1973,7 @@ async fn check_balance_too_low_err< } None => { if force { - edisplay!( + edisplay_line!( IO, "No balance found for the source {} of token {}", source, @@ -1994,7 +1994,7 @@ fn validate_untrusted_code_err( ) -> Result<(), Error> { if let Err(err) = vm::validate_untrusted_wasm(vp_code) { if force { - edisplay!( + edisplay_line!( IO, "Validity predicate code validation failed with {}", err diff --git a/shared/src/types/io.rs b/shared/src/types/io.rs index 3f130887da..72904ac114 100644 --- a/shared/src/types/io.rs +++ b/shared/src/types/io.rs @@ -110,7 +110,7 @@ macro_rules! display_line { /// Convenience macro for formatting arguments to /// [`Io::eprintln`] #[macro_export] -macro_rules! edisplay { +macro_rules! edisplay_line { ($io:ty,$($args:tt)*) => { <$io>::eprintln(format_args!($($args)*).to_string()) }; From c5a2ce2215f464ede671889b580a00d1ffdaa5a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Tue, 25 Jul 2023 08:23:29 +0100 Subject: [PATCH 4/9] changelog: add #1746 --- .changelog/unreleased/features/1746-generic-io.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changelog/unreleased/features/1746-generic-io.md diff --git a/.changelog/unreleased/features/1746-generic-io.md b/.changelog/unreleased/features/1746-generic-io.md new file mode 100644 index 0000000000..ff469ec863 --- /dev/null +++ b/.changelog/unreleased/features/1746-generic-io.md @@ -0,0 +1,2 @@ +- Replaced standard IO in SDK and client code with a trait that allows custom + handling. ([\#1746](https://github.com/anoma/namada/pull/1746)) \ No newline at end of file From cfb57ab19234c53dcca18d8164fccaa81c5e3551 Mon Sep 17 00:00:00 2001 From: satan Date: Wed, 26 Jul 2023 13:26:36 +0200 Subject: [PATCH 5/9] [feat]: Made io reading methods async --- apps/src/lib/cli/api.rs | 2 ++ shared/src/ledger/eth_bridge/bridge_pool.rs | 2 +- shared/src/types/io.rs | 6 ++++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/src/lib/cli/api.rs b/apps/src/lib/cli/api.rs index c53f277e29..2cf609f18e 100644 --- a/apps/src/lib/cli/api.rs +++ b/apps/src/lib/cli/api.rs @@ -28,6 +28,8 @@ impl CliClient for HttpClient { } pub struct CliIo; + +#[async_trait::async_trait(?Send)] impl Io for CliIo {} pub struct CliApi(PhantomData); diff --git a/shared/src/ledger/eth_bridge/bridge_pool.rs b/shared/src/ledger/eth_bridge/bridge_pool.rs index 4891468e58..235941eb6a 100644 --- a/shared/src/ledger/eth_bridge/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/bridge_pool.rs @@ -221,7 +221,7 @@ where display!(IO, "\nDo you wish to proceed? (y/n): "); IO::flush(); loop { - let resp = IO::read().try_halt(|e| { + let resp = IO::read().await.try_halt(|e| { display_line!( IO, "Encountered error reading from STDIN: {e:?}" diff --git a/shared/src/types/io.rs b/shared/src/types/io.rs index 72904ac114..80eeb2eb69 100644 --- a/shared/src/types/io.rs +++ b/shared/src/types/io.rs @@ -5,8 +5,10 @@ /// Rust native I/O handling. pub struct DefaultIo; +#[async_trait::async_trait(?Send)] impl Io for DefaultIo {} +#[async_trait::async_trait(?Send)] #[allow(missing_docs)] pub trait Io { fn print(output: impl AsRef) { @@ -40,11 +42,11 @@ pub trait Io { eprintln!("{}", output.as_ref()); } - fn read() -> std::io::Result { + async fn read() -> std::io::Result { read_aux(std::io::stdin().lock()) } - fn prompt(question: impl AsRef) -> String { + async fn prompt(question: impl AsRef) -> String { prompt_aux( std::io::stdin().lock(), std::io::stdout(), From 36fe43e3d1c35455034446873fbc47cbdab37d37 Mon Sep 17 00:00:00 2001 From: satan Date: Thu, 27 Jul 2023 14:36:31 +0200 Subject: [PATCH 6/9] [feat]: Changed default io read methods to use tokio's async io tools --- shared/src/types/io.rs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/shared/src/types/io.rs b/shared/src/types/io.rs index 80eeb2eb69..c4d2231dee 100644 --- a/shared/src/types/io.rs +++ b/shared/src/types/io.rs @@ -47,25 +47,29 @@ pub trait Io { } async fn prompt(question: impl AsRef) -> String { - prompt_aux( - std::io::stdin().lock(), - std::io::stdout(), - question.as_ref(), - ) + prompt_aux(tokio::io::stdin(), tokio::io::stdout(), question.as_ref()) + .await } } /// A generic function for displaying a prompt to users and reading /// in their response. -pub fn prompt_aux(mut reader: R, mut writer: W, question: &str) -> String +pub async fn prompt_aux( + mut reader: R, + mut writer: W, + question: &str, +) -> String where - R: std::io::Read, - W: std::io::Write, + R: tokio::io::AsyncReadExt + Unpin, + W: tokio::io::AsyncWriteExt + Unpin, { - write!(&mut writer, "{}", question).expect("Unable to write"); - writer.flush().unwrap(); + writer + .write_all(question.as_bytes()) + .await + .expect("Unable to write"); + writer.flush().await.unwrap(); let mut s = String::new(); - reader.read_to_string(&mut s).expect("Unable to read"); + reader.read_to_string(&mut s).await.expect("Unable to read"); s } From f0467289f85b0970db5cd228a01e790bbfdbd84a Mon Sep 17 00:00:00 2001 From: satan Date: Thu, 27 Jul 2023 14:41:23 +0200 Subject: [PATCH 7/9] [feat]: Changed default io read methods to use tokio's async io tools --- shared/src/types/io.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/shared/src/types/io.rs b/shared/src/types/io.rs index c4d2231dee..93d45a75ff 100644 --- a/shared/src/types/io.rs +++ b/shared/src/types/io.rs @@ -42,8 +42,8 @@ pub trait Io { eprintln!("{}", output.as_ref()); } - async fn read() -> std::io::Result { - read_aux(std::io::stdin().lock()) + async fn read() -> tokio::io::Result { + read_aux(tokio::io::stdin()).await } async fn prompt(question: impl AsRef) -> String { @@ -74,12 +74,12 @@ where } /// A generic function for reading input from users -pub fn read_aux(mut reader: R) -> std::io::Result +pub async fn read_aux(mut reader: R) -> tokio::io::Result where - R: std::io::Read, + R: tokio::io::AsyncReadExt + Unpin, { let mut s = String::new(); - reader.read_to_string(&mut s)?; + reader.read_to_string(&mut s).await?; Ok(s) } From c8556323097c0171d250f4f6c1956a6ebcd92231 Mon Sep 17 00:00:00 2001 From: satan Date: Tue, 15 Aug 2023 10:32:15 +0200 Subject: [PATCH 8/9] [fix]: Removed unused file --- apps/src/bin/namada-client/cli.rs | 500 ------------------------------ 1 file changed, 500 deletions(-) delete mode 100644 apps/src/bin/namada-client/cli.rs diff --git a/apps/src/bin/namada-client/cli.rs b/apps/src/bin/namada-client/cli.rs deleted file mode 100644 index d6a3cbdaf9..0000000000 --- a/apps/src/bin/namada-client/cli.rs +++ /dev/null @@ -1,500 +0,0 @@ -//! Namada client CLI. - -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::{signing, tx as sdk_tx}; -use namada::types::control_flow::ProceedOrElse; -use namada_apps::cli; -use namada_apps::cli::args::CliToSdk; -use namada_apps::cli::cmds::*; -use namada_apps::client::{rpc, tx, utils}; -use namada_apps::facade::tendermint_rpc::HttpClient; - -fn error() -> Report { - eyre!("Fatal error") -} - -pub async fn main() -> Result<()> { - match cli::namada_client_cli()? { - cli::NamadaClient::WithContext(cmd_box) => { - let (cmd, mut ctx) = *cmd_box; - use NamadaClientWithContext as Sub; - match cmd { - // Ledger cmds - Sub::TxCustom(TxCustom(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - let dry_run = args.tx.dry_run; - tx::submit_custom::(&client, &mut ctx, args) - .await?; - if !dry_run { - namada_apps::wallet::save(&ctx.wallet) - .unwrap_or_else(|err| eprintln!("{}", err)); - } else { - println!( - "Transaction dry run. No addresses have been \ - saved." - ) - } - } - Sub::TxTransfer(TxTransfer(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_transfer(&client, ctx, args).await?; - } - Sub::TxIbcTransfer(TxIbcTransfer(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_ibc_transfer::(&client, ctx, args) - .await?; - } - Sub::TxUpdateVp(TxUpdateVp(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_update_vp::(&client, &mut ctx, args) - .await?; - } - Sub::TxInitAccount(TxInitAccount(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - let dry_run = args.tx.dry_run; - tx::submit_init_account::( - &client, &mut ctx, args, - ) - .await?; - if !dry_run { - namada_apps::wallet::save(&ctx.wallet) - .unwrap_or_else(|err| eprintln!("{}", err)); - } else { - println!( - "Transaction dry run. No addresses have been \ - saved." - ) - } - } - Sub::TxInitValidator(TxInitValidator(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_init_validator::(&client, ctx, args) - .await?; - } - Sub::TxInitProposal(TxInitProposal(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_init_proposal::(&client, ctx, args) - .await?; - } - Sub::TxVoteProposal(TxVoteProposal(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_vote_proposal::(&client, ctx, args) - .await?; - } - Sub::TxRevealPk(TxRevealPk(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_reveal_pk::(&client, &mut ctx, args) - .await?; - } - Sub::Bond(Bond(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_bond::(&client, &mut ctx, args) - .await?; - } - Sub::Unbond(Unbond(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_unbond::(&client, &mut ctx, args) - .await?; - } - Sub::Withdraw(Withdraw(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_withdraw::(&client, ctx, args) - .await?; - } - Sub::TxCommissionRateChange(TxCommissionRateChange( - mut args, - )) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client).await; - let args = args.to_sdk(&mut ctx); - tx::submit_validator_commission_change::( - &client, ctx, args, - ) - .await?; - } - // Eth bridge - Sub::AddToEthBridgePool(args) => { - let mut args = args.0; - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - let tx_args = args.tx.clone(); - let (mut tx, addr, pk) = bridge_pool::build_bridge_pool_tx( - &client, - &mut ctx.wallet, - args, - ) - .await - .unwrap(); - tx::submit_reveal_aux( - &client, - &mut ctx, - &tx_args, - addr, - pk.clone(), - &mut tx, - ) - .await?; - signing::sign_tx(&mut ctx.wallet, &mut tx, &tx_args, &pk) - .await?; - sdk_tx::process_tx(&client, &mut ctx.wallet, &tx_args, tx) - .await?; - } - Sub::TxUnjailValidator(TxUnjailValidator(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_unjail_validator::( - &client, ctx, args, - ) - .await?; - } - // Ledger queries - Sub::QueryEpoch(QueryEpoch(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - rpc::query_and_print_epoch(&client).await; - } - Sub::QueryTransfers(QueryTransfers(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_transfers( - &client, - &mut ctx.wallet, - &mut ctx.shielded, - args, - ) - .await; - } - Sub::QueryConversions(QueryConversions(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_conversions(&client, &mut ctx.wallet, args) - .await; - } - Sub::QueryBlock(QueryBlock(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - rpc::query_block(&client).await; - } - Sub::QueryBalance(QueryBalance(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_balance( - &client, - &mut ctx.wallet, - &mut ctx.shielded, - args, - ) - .await; - } - Sub::QueryBonds(QueryBonds(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_bonds(&client, &mut ctx.wallet, args) - .await - .expect("expected successful query of bonds"); - } - Sub::QueryBondedStake(QueryBondedStake(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_bonded_stake(&client, args).await; - } - Sub::QueryValidatorState(QueryValidatorState(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_and_print_validator_state( - &client, - &mut ctx.wallet, - args, - ) - .await; - } - Sub::QueryCommissionRate(QueryCommissionRate(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_and_print_commission_rate( - &client, - &mut ctx.wallet, - args, - ) - .await; - } - Sub::QuerySlashes(QuerySlashes(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_slashes(&client, &mut ctx.wallet, args).await; - } - Sub::QueryDelegations(QueryDelegations(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_delegations(&client, &mut ctx.wallet, args) - .await; - } - Sub::QueryFindValidator(QueryFindValidator(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_find_validator(&client, args).await; - } - Sub::QueryResult(QueryResult(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_result(&client, args).await; - } - Sub::QueryRawBytes(QueryRawBytes(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_raw_bytes(&client, args).await; - } - - Sub::QueryProposal(QueryProposal(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_proposal(&client, args).await; - } - Sub::QueryProposalResult(QueryProposalResult(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_proposal_result(&client, args).await; - } - Sub::QueryProtocolParameters(QueryProtocolParameters( - mut args, - )) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_protocol_parameters(&client, args).await; - } - } - } - cli::NamadaClient::WithoutContext(cmd, global_args) => match cmd { - // Utils cmds - Utils::JoinNetwork(JoinNetwork(args)) => { - utils::join_network(global_args, args).await - } - Utils::FetchWasms(FetchWasms(args)) => { - utils::fetch_wasms(global_args, args).await - } - Utils::InitNetwork(InitNetwork(args)) => { - utils::init_network(global_args, args) - } - Utils::InitGenesisValidator(InitGenesisValidator(args)) => { - utils::init_genesis_validator(global_args, args) - } - Utils::PkToTmAddress(PkToTmAddress(args)) => { - utils::pk_to_tm_address(global_args, args) - } - Utils::DefaultBaseDir(DefaultBaseDir(args)) => { - utils::default_base_dir(global_args, args) - } - Utils::EpochSleep(EpochSleep(args)) => { - let mut ctx = cli::Context::new(global_args) - .expect("expected to construct a context"); - let ledger_address = args.ledger_address.clone(); - wait_until_node_is_synched(&ledger_address).await; - let client = HttpClient::new(ledger_address).unwrap(); - let args = args.to_sdk(&mut ctx); - rpc::epoch_sleep(&client, args).await; - } - }, - } - Ok(()) -} From 078cea076f0d43525bffba7021879875fb813fff Mon Sep 17 00:00:00 2001 From: satan Date: Fri, 1 Sep 2023 09:17:04 +0200 Subject: [PATCH 9/9] [chore]: Merge in 0.21.1 --- .../v0.21.0/bug-fixes/1774-fix-dec-display.md | 2 + .../bug-fixes/1775-downgrade-sysinfo.md | 2 + .../v0.21.0/bug-fixes/1793-fix-unjail-bug.md | 4 + .../bug-fixes/1801-fix-available-memory.md | 2 + ...1765-multisignature-draft-rebase-0.20.0.md | 4 + .../features/1803-refactor-governance.md | 2 + .changelog/v0.21.0/summary.md | 2 + .../testing/1768-pregen-masp-proofs.md | 2 + .changelog/v0.21.1/bug-fixes/1816-pgf-v2.md | 2 + .../v0.21.1/features/1635-ibc-rs-0.41.0.md | 2 + .changelog/v0.21.1/summary.md | 1 + .github/workflows/build-and-test.yml | 7 + .github/workflows/scripts/e2e.json | 2 +- CHANGELOG.md | 46 + Cargo.lock | 729 ++------ Cargo.toml | 8 +- Makefile | 23 +- README.md | 8 +- apps/src/bin/namada-client/cli.rs | 0 apps/src/bin/namada/cli.rs | 2 +- apps/src/lib/cli.rs | 623 +++++-- apps/src/lib/cli/client.rs | 120 +- apps/src/lib/cli/utils.rs | 21 + apps/src/lib/client/mod.rs | 1 - apps/src/lib/client/rpc.rs | 908 ++++------ apps/src/lib/client/signing.rs | 4 +- apps/src/lib/client/tx.rs | 1552 ++++++++--------- apps/src/lib/config/genesis.rs | 59 +- apps/src/lib/config/mod.rs | 2 +- apps/src/lib/node/ledger/mod.rs | 10 +- .../lib/node/ledger/shell/finalize_block.rs | 149 +- apps/src/lib/node/ledger/shell/governance.rs | 503 ++++-- apps/src/lib/node/ledger/shell/init_chain.rs | 41 +- apps/src/lib/node/ledger/shell/mod.rs | 140 +- .../lib/node/ledger/shell/prepare_proposal.rs | 146 +- .../lib/node/ledger/shell/process_proposal.rs | 337 ++-- apps/src/lib/node/ledger/shell/utils.rs | 14 + apps/src/lib/wallet/defaults.rs | 6 +- core/Cargo.toml | 5 +- core/src/ledger/governance/cli/mod.rs | 6 + core/src/ledger/governance/cli/offline.rs | 389 +++++ core/src/ledger/governance/cli/onchain.rs | 333 ++++ core/src/ledger/governance/cli/utils.rs | 0 core/src/ledger/governance/cli/validation.rs | 259 +++ core/src/ledger/governance/mod.rs | 4 + core/src/ledger/governance/parameters.rs | 51 +- .../{storage.rs => storage/keys.rs} | 145 +- core/src/ledger/governance/storage/mod.rs | 6 + .../src/ledger/governance/storage/proposal.rs | 270 +++ core/src/ledger/governance/storage/vote.rs | 127 ++ core/src/ledger/governance/utils.rs | 291 ++++ core/src/ledger/ibc/context/common.rs | 16 +- core/src/ledger/ibc/context/execution.rs | 42 +- core/src/ledger/ibc/context/router.rs | 3 +- core/src/ledger/ibc/context/transfer_mod.rs | 17 +- core/src/ledger/ibc/context/validation.rs | 24 +- core/src/ledger/ibc/mod.rs | 82 +- core/src/ledger/ibc/storage.rs | 48 +- core/src/ledger/mod.rs | 2 +- core/src/ledger/parameters/mod.rs | 45 + core/src/ledger/parameters/storage.rs | 6 + core/src/ledger/{slash_fund => pgf}/mod.rs | 11 +- core/src/ledger/pgf/parameters.rs | 63 + core/src/ledger/pgf/storage/keys.rs | 67 + core/src/ledger/pgf/storage/mod.rs | 2 + core/src/ledger/slash_fund/storage.rs | 8 - core/src/ledger/storage/mod.rs | 1 + core/src/ledger/storage_api/account.rs | 106 ++ core/src/ledger/storage_api/governance.rs | 145 +- core/src/ledger/storage_api/key.rs | 24 +- core/src/ledger/storage_api/mod.rs | 2 + core/src/ledger/storage_api/pgf.rs | 30 + core/src/ledger/storage_api/token.rs | 32 + core/src/proto/mod.rs | 5 +- core/src/proto/types.rs | 497 +++++- core/src/types/account.rs | 92 + core/src/types/address.rs | 24 +- core/src/types/dec.rs | 10 +- core/src/types/governance.rs | 384 ---- core/src/types/ibc.rs | 6 +- core/src/types/key/mod.rs | 75 +- core/src/types/mod.rs | 2 +- core/src/types/token.rs | 19 + core/src/types/transaction/account.rs | 52 + core/src/types/transaction/governance.rs | 185 +- core/src/types/transaction/mod.rs | 103 +- core/src/types/transaction/pos.rs | 40 + core/src/types/transaction/protocol.rs | 4 +- core/src/types/transaction/wrapper.rs | 32 +- .../src/explore/design/ledger/governance.md | 10 +- .../src/specs/ledger/default-transactions.md | 2 +- encoding_spec/src/main.rs | 21 +- genesis/dev.toml | 250 ++- genesis/e2e-tests-single-node.toml | 14 +- proof_of_stake/src/lib.rs | 9 +- proof_of_stake/src/tests.rs | 147 +- scripts/generator.sh | 66 +- scripts/get_hermes.sh | 41 + shared/src/ledger/args.rs | 117 +- shared/src/ledger/eth_bridge/bridge_pool.rs | 80 +- shared/src/ledger/events.rs | 6 +- shared/src/ledger/events/log/dumb_queries.rs | 5 +- .../ledger/{native_vp => }/governance/mod.rs | 633 ++++--- shared/src/ledger/governance/utils.rs | 122 ++ shared/src/ledger/ibc/vp/mod.rs | 563 +++--- shared/src/ledger/masp.rs | 169 +- shared/src/ledger/mod.rs | 4 +- .../ethereum_bridge/bridge_pool_vp.rs | 37 +- .../ledger/native_vp/ethereum_bridge/vp.rs | 6 +- .../src/ledger/native_vp/governance/utils.rs | 484 ----- shared/src/ledger/native_vp/mod.rs | 2 - shared/src/ledger/native_vp/multitoken.rs | 2 +- shared/src/ledger/native_vp/parameters.rs | 11 +- shared/src/ledger/pgf/mod.rs | 126 ++ shared/src/ledger/pgf/utils.rs | 66 + shared/src/ledger/pos/vp.rs | 11 +- shared/src/ledger/protocol/mod.rs | 26 +- shared/src/ledger/queries/shell.rs | 50 +- shared/src/ledger/queries/vp/governance.rs | 38 + shared/src/ledger/queries/vp/mod.rs | 8 + shared/src/ledger/queries/vp/pgf.rs | 36 + shared/src/ledger/queries/vp/pos.rs | 4 +- shared/src/ledger/rpc.rs | 184 +- shared/src/ledger/signing.rs | 571 +++--- shared/src/ledger/tx.rs | 1330 +++++++------- shared/src/types/mod.rs | 4 +- shared/src/vm/wasm/run.rs | 67 +- ...C83E76506147445D4DC22D57CBC9869BCDDA80.bin | Bin 0 -> 9649 bytes ...5D4C1BF345378A4FB6BB0B179BA8BDB0D2A3C0.bin | Bin 0 -> 9208 bytes ...9CB1712CCA85B0E96A3330A63BE7CD9E5ECD22.bin | Bin 0 -> 7448 bytes ...8B269A5436CD72AA758686960F409B04841707.bin | Bin 0 -> 9208 bytes ...79BAC90BA1F01653EBCFDCF7CC8AAA1BBEE462.bin | Bin 0 -> 25031 bytes ...7C98D1E5AAAA9988F26B1A47090ACCE693572F.bin | Bin 0 -> 7448 bytes ...4FDED28D5E7D3C6B52DCF38A5978CEA70D6FD3.bin | Bin 0 -> 9649 bytes ...46763B3CE0BACFB7799C6744E50B9E7F43E961.bin | Bin 0 -> 17018 bytes ...2989556FD771D368849D034E22923FD350EEEC.bin | Bin 0 -> 19947 bytes ...1C0CA6AA6520A2AC8BC34A84358EA137F138D0.bin | Bin 0 -> 18792 bytes ...8DC6BBB31619C7E93A1A5A2E64B694DBE1BD6E.bin | Bin 0 -> 7448 bytes ...344FFFAA6CA273027CD480AEA68DDED57D88CA.bin | Bin 0 -> 7448 bytes test_fixtures/masp_proofs/README.md | 11 + test_utils/src/lib.rs | 2 - tests/Cargo.toml | 4 +- tests/src/e2e/eth_bridge_tests.rs | 16 +- tests/src/e2e/eth_bridge_tests/helpers.rs | 2 +- tests/src/e2e/helpers.rs | 6 + tests/src/e2e/ibc_tests.rs | 942 +++++----- tests/src/e2e/ledger_tests.rs | 690 +++----- tests/src/e2e/multitoken_tests.rs | 372 ++++ tests/src/e2e/multitoken_tests/helpers.rs | 190 ++ tests/src/e2e/setup.rs | 1 + tests/src/integration/masp.rs | 8 +- tests/src/native_vp/eth_bridge_pool.rs | 16 +- tests/src/native_vp/pos.rs | 5 + tests/src/vm_host_env/ibc.rs | 148 +- tests/src/vm_host_env/mod.rs | 421 +++-- tests/src/vm_host_env/tx.rs | 52 +- tests/src/vm_host_env/vp.rs | 2 +- tx_prelude/src/account.rs | 18 + tx_prelude/src/lib.rs | 2 +- tx_prelude/src/proof_of_stake.rs | 13 +- vp_prelude/src/lib.rs | 25 +- wasm/Cargo.lock | 1004 ++--------- wasm/checksums.json | 38 +- wasm/tx_template/Cargo.toml | 2 +- wasm/tx_template/src/lib.rs | 2 +- wasm/vp_template/Cargo.toml | 2 +- wasm/wasm_source/Cargo.toml | 4 +- wasm/wasm_source/Makefile | 2 +- wasm/wasm_source/src/lib.rs | 4 +- wasm/wasm_source/src/tx_bond.rs | 17 +- .../src/tx_change_validator_commission.rs | 17 +- wasm/wasm_source/src/tx_init_account.rs | 15 +- wasm/wasm_source/src/tx_init_proposal.rs | 10 +- wasm/wasm_source/src/tx_init_validator.rs | 2 +- wasm/wasm_source/src/tx_unbond.rs | 16 +- wasm/wasm_source/src/tx_update_account.rs | 45 + wasm/wasm_source/src/tx_withdraw.rs | 16 +- wasm/wasm_source/src/vp_implicit.rs | 146 +- wasm/wasm_source/src/vp_testnet_faucet.rs | 48 +- wasm/wasm_source/src/vp_user.rs | 142 +- wasm/wasm_source/src/vp_validator.rs | 141 +- wasm_for_tests/tx_memory_limit.wasm | Bin 433802 -> 444310 bytes wasm_for_tests/tx_mint_tokens.wasm | Bin 595912 -> 595637 bytes wasm_for_tests/tx_no_op.wasm | Bin 355254 -> 364702 bytes wasm_for_tests/tx_proposal_code.wasm | Bin 518649 -> 528038 bytes wasm_for_tests/tx_read_storage_key.wasm | Bin 438326 -> 450586 bytes wasm_for_tests/tx_write.wasm | Bin 441531 -> 451937 bytes wasm_for_tests/vp_always_false.wasm | Bin 409996 -> 419074 bytes wasm_for_tests/vp_always_true.wasm | Bin 409996 -> 419074 bytes wasm_for_tests/vp_eval.wasm | Bin 480020 -> 492706 bytes wasm_for_tests/vp_memory_limit.wasm | Bin 458484 -> 468787 bytes wasm_for_tests/vp_read_storage_key.wasm | Bin 463802 -> 475686 bytes wasm_for_tests/wasm_source/Cargo.lock | 996 ++--------- wasm_for_tests/wasm_source/Cargo.toml | 3 +- wasm_for_tests/wasm_source/Makefile | 1 - wasm_for_tests/wasm_source/src/lib.rs | 26 +- 196 files changed, 11236 insertions(+), 9409 deletions(-) create mode 100644 .changelog/v0.21.0/bug-fixes/1774-fix-dec-display.md create mode 100644 .changelog/v0.21.0/bug-fixes/1775-downgrade-sysinfo.md create mode 100644 .changelog/v0.21.0/bug-fixes/1793-fix-unjail-bug.md create mode 100644 .changelog/v0.21.0/bug-fixes/1801-fix-available-memory.md create mode 100644 .changelog/v0.21.0/features/1765-multisignature-draft-rebase-0.20.0.md create mode 100644 .changelog/v0.21.0/features/1803-refactor-governance.md create mode 100644 .changelog/v0.21.0/summary.md create mode 100644 .changelog/v0.21.0/testing/1768-pregen-masp-proofs.md create mode 100644 .changelog/v0.21.1/bug-fixes/1816-pgf-v2.md create mode 100644 .changelog/v0.21.1/features/1635-ibc-rs-0.41.0.md create mode 100644 .changelog/v0.21.1/summary.md create mode 100644 apps/src/bin/namada-client/cli.rs create mode 100644 apps/src/lib/node/ledger/shell/utils.rs create mode 100644 core/src/ledger/governance/cli/mod.rs create mode 100644 core/src/ledger/governance/cli/offline.rs create mode 100644 core/src/ledger/governance/cli/onchain.rs create mode 100644 core/src/ledger/governance/cli/utils.rs create mode 100644 core/src/ledger/governance/cli/validation.rs rename core/src/ledger/governance/{storage.rs => storage/keys.rs} (78%) create mode 100644 core/src/ledger/governance/storage/mod.rs create mode 100644 core/src/ledger/governance/storage/proposal.rs create mode 100644 core/src/ledger/governance/storage/vote.rs create mode 100644 core/src/ledger/governance/utils.rs rename core/src/ledger/{slash_fund => pgf}/mod.rs (55%) create mode 100644 core/src/ledger/pgf/parameters.rs create mode 100644 core/src/ledger/pgf/storage/keys.rs create mode 100644 core/src/ledger/pgf/storage/mod.rs delete mode 100644 core/src/ledger/slash_fund/storage.rs create mode 100644 core/src/ledger/storage_api/account.rs create mode 100644 core/src/ledger/storage_api/pgf.rs create mode 100644 core/src/types/account.rs delete mode 100644 core/src/types/governance.rs create mode 100644 core/src/types/transaction/account.rs create mode 100755 scripts/get_hermes.sh rename shared/src/ledger/{native_vp => }/governance/mod.rs (50%) create mode 100644 shared/src/ledger/governance/utils.rs delete mode 100644 shared/src/ledger/native_vp/governance/utils.rs create mode 100644 shared/src/ledger/pgf/mod.rs create mode 100644 shared/src/ledger/pgf/utils.rs create mode 100644 shared/src/ledger/queries/vp/governance.rs create mode 100644 shared/src/ledger/queries/vp/pgf.rs create mode 100644 test_fixtures/masp_proofs/0DAF8BDF2318129AC828A7149AC83E76506147445D4DC22D57CBC9869BCDDA80.bin create mode 100644 test_fixtures/masp_proofs/12C933751C24BDC39C9108F5AF5D4C1BF345378A4FB6BB0B179BA8BDB0D2A3C0.bin create mode 100644 test_fixtures/masp_proofs/1362F1CF9B836CF8B05D8189EA9CB1712CCA85B0E96A3330A63BE7CD9E5ECD22.bin create mode 100644 test_fixtures/masp_proofs/5B99F3D7E0CE75AB1F4B737EC88B269A5436CD72AA758686960F409B04841707.bin create mode 100644 test_fixtures/masp_proofs/889C046FA76727BC97433503BB79BAC90BA1F01653EBCFDCF7CC8AAA1BBEE462.bin create mode 100644 test_fixtures/masp_proofs/8B29BC2E1A96DF331C7C3A2B227C98D1E5AAAA9988F26B1A47090ACCE693572F.bin create mode 100644 test_fixtures/masp_proofs/A9FA2730222946FA51E9D587544FDED28D5E7D3C6B52DCF38A5978CEA70D6FD3.bin create mode 100644 test_fixtures/masp_proofs/AC308C08512AF5DAA364B845D146763B3CE0BACFB7799C6744E50B9E7F43E961.bin create mode 100644 test_fixtures/masp_proofs/BE57BA4D8FB068F5A933E78DEF2989556FD771D368849D034E22923FD350EEEC.bin create mode 100644 test_fixtures/masp_proofs/E76E54B7526CD2B5423322FB711C0CA6AA6520A2AC8BC34A84358EA137F138D0.bin create mode 100644 test_fixtures/masp_proofs/EE7C912B7E21F07494D58AA6668DC6BBB31619C7E93A1A5A2E64B694DBE1BD6E.bin create mode 100644 test_fixtures/masp_proofs/F068FDF05B8F25DD923E667215344FFFAA6CA273027CD480AEA68DDED57D88CA.bin create mode 100644 test_fixtures/masp_proofs/README.md create mode 100644 tests/src/e2e/multitoken_tests.rs create mode 100644 tests/src/e2e/multitoken_tests/helpers.rs create mode 100644 tx_prelude/src/account.rs create mode 100644 wasm/wasm_source/src/tx_update_account.rs diff --git a/.changelog/v0.21.0/bug-fixes/1774-fix-dec-display.md b/.changelog/v0.21.0/bug-fixes/1774-fix-dec-display.md new file mode 100644 index 0000000000..c53de24bee --- /dev/null +++ b/.changelog/v0.21.0/bug-fixes/1774-fix-dec-display.md @@ -0,0 +1,2 @@ +- Fixes buggy Display for the Dec type when the number is some multiple of 10 + ([\#1774](https://github.com/anoma/namada/pull/1774)) \ No newline at end of file diff --git a/.changelog/v0.21.0/bug-fixes/1775-downgrade-sysinfo.md b/.changelog/v0.21.0/bug-fixes/1775-downgrade-sysinfo.md new file mode 100644 index 0000000000..4d45e30a0a --- /dev/null +++ b/.changelog/v0.21.0/bug-fixes/1775-downgrade-sysinfo.md @@ -0,0 +1,2 @@ +- Downgraded sysinfo back to v0.27.8 with a working available memory report on + Mac M1. ([\#1775](https://github.com/anoma/namada/pull/1775)) \ No newline at end of file diff --git a/.changelog/v0.21.0/bug-fixes/1793-fix-unjail-bug.md b/.changelog/v0.21.0/bug-fixes/1793-fix-unjail-bug.md new file mode 100644 index 0000000000..11a2b1e545 --- /dev/null +++ b/.changelog/v0.21.0/bug-fixes/1793-fix-unjail-bug.md @@ -0,0 +1,4 @@ +- Fixes buggy error handling in pos unjail_validator. Now properly enforces that + if an unjail tx is submitted when the validator state is something other than + Jailed in any of the current or future epochs, the tx will error out and fail. + ([\#1793](https://github.com/anoma/namada/pull/1793)) \ No newline at end of file diff --git a/.changelog/v0.21.0/bug-fixes/1801-fix-available-memory.md b/.changelog/v0.21.0/bug-fixes/1801-fix-available-memory.md new file mode 100644 index 0000000000..4f4e1b39ca --- /dev/null +++ b/.changelog/v0.21.0/bug-fixes/1801-fix-available-memory.md @@ -0,0 +1,2 @@ +- Fix available_memory size + ([\#1801](https://github.com/anoma/namada/issues/1801)) \ No newline at end of file diff --git a/.changelog/v0.21.0/features/1765-multisignature-draft-rebase-0.20.0.md b/.changelog/v0.21.0/features/1765-multisignature-draft-rebase-0.20.0.md new file mode 100644 index 0000000000..25697effb8 --- /dev/null +++ b/.changelog/v0.21.0/features/1765-multisignature-draft-rebase-0.20.0.md @@ -0,0 +1,4 @@ +- Introduce multisignature accounts and transaction format. It is now possible + to supply multiple public keys when creating a new account/validator and + specify the minimum number of signatures required to authorize a transaction. + ([\#1765](https://github.com/anoma/namada/pull/1765)) \ No newline at end of file diff --git a/.changelog/v0.21.0/features/1803-refactor-governance.md b/.changelog/v0.21.0/features/1803-refactor-governance.md new file mode 100644 index 0000000000..5ef7160505 --- /dev/null +++ b/.changelog/v0.21.0/features/1803-refactor-governance.md @@ -0,0 +1,2 @@ +- Introduce a simplified version of Public Good Fundings. + ([\#1803](https://github.com/anoma/namada/pull/1803)) \ No newline at end of file diff --git a/.changelog/v0.21.0/summary.md b/.changelog/v0.21.0/summary.md new file mode 100644 index 0000000000..bd8061518c --- /dev/null +++ b/.changelog/v0.21.0/summary.md @@ -0,0 +1,2 @@ +Namada 0.21.0 is a minor release introducing a first version of the PGF mechanism, addressing several +improvements to the PoS and Governance system and some changes to the ledger stability. diff --git a/.changelog/v0.21.0/testing/1768-pregen-masp-proofs.md b/.changelog/v0.21.0/testing/1768-pregen-masp-proofs.md new file mode 100644 index 0000000000..7f86b1621f --- /dev/null +++ b/.changelog/v0.21.0/testing/1768-pregen-masp-proofs.md @@ -0,0 +1,2 @@ +- Added pre-built MASP proofs for integration tests. + ([\#1768](https://github.com/anoma/namada/pull/1768)) \ No newline at end of file diff --git a/.changelog/v0.21.1/bug-fixes/1816-pgf-v2.md b/.changelog/v0.21.1/bug-fixes/1816-pgf-v2.md new file mode 100644 index 0000000000..bede5e354e --- /dev/null +++ b/.changelog/v0.21.1/bug-fixes/1816-pgf-v2.md @@ -0,0 +1,2 @@ +- Introduce a new genesis section to control PGF storage at chain start. + ([\#1816](https://github.com/anoma/namada/pull/1816)) \ No newline at end of file diff --git a/.changelog/v0.21.1/features/1635-ibc-rs-0.41.0.md b/.changelog/v0.21.1/features/1635-ibc-rs-0.41.0.md new file mode 100644 index 0000000000..f1d1fddc92 --- /dev/null +++ b/.changelog/v0.21.1/features/1635-ibc-rs-0.41.0.md @@ -0,0 +1,2 @@ +- Support the memo field of IBC transfer + ([\#1635](https://github.com/anoma/namada/issues/1635)) \ No newline at end of file diff --git a/.changelog/v0.21.1/summary.md b/.changelog/v0.21.1/summary.md new file mode 100644 index 0000000000..27efa15457 --- /dev/null +++ b/.changelog/v0.21.1/summary.md @@ -0,0 +1 @@ +Namada 0.21.0 is a patch release addressing some minor changes to the PGF and IBC components. diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index b8a796dfc6..4419069531 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -394,6 +394,7 @@ jobs: nightly_version: [nightly-2023-06-01] mold_version: [1.7.0] comet_bft: [0.37.2] + hermes: [1.6.0-namada-beta1] make: - name: e2e suffix: '' @@ -525,6 +526,11 @@ jobs: curl -o cometbft.tar.gz -LO https://github.com/cometbft/cometbft/releases/download/v${{ matrix.comet_bft }}/cometbft_${{ matrix.comet_bft }}_linux_amd64.tar.gz tar -xvzf cometbft.tar.gz mv cometbft /usr/local/bin + - name: Download Hermes + run: | + curl -o hermes.tar.gz -LO https://github.com/heliaxdev/hermes/releases/download/v${{ matrix.hermes }}/hermes-v${{ matrix.hermes }}-x86_64-unknown-linux-gnu.tar.gz + tar -xvzf hermes.tar.gz + mv hermes /usr/local/bin - name: Change permissions run: | chmod +x target/release/namada @@ -532,6 +538,7 @@ jobs: chmod +x target/release/namadan chmod +x target/release/namadac chmod +x /usr/local/bin/cometbft + chmod +x /usr/local/bin/hermes - name: Run e2e test run: | python3 .github/workflows/scripts/schedule-e2e.py diff --git a/.github/workflows/scripts/e2e.json b/.github/workflows/scripts/e2e.json index 485e4b43ad..15b871e61b 100644 --- a/.github/workflows/scripts/e2e.json +++ b/.github/workflows/scripts/e2e.json @@ -8,10 +8,10 @@ "e2e::ledger_tests::ledger_txs_and_queries": 30, "e2e::ledger_tests::masp_txs_and_queries": 82, "e2e::ledger_tests::pos_bonds": 77, + "e2e::ledger_tests::implicit_account_reveal_pk": 30, "e2e::ledger_tests::pos_init_validator": 40, "e2e::ledger_tests::proposal_offline": 21, "e2e::ledger_tests::pgf_governance_proposal": 100, - "e2e::ledger_tests::eth_governance_proposal": 100, "e2e::ledger_tests::proposal_submission": 200, "e2e::ledger_tests::run_ledger": 5, "e2e::ledger_tests::run_ledger_load_state_and_reset": 23, diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ad3c0eff0..8c059ef2eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,51 @@ # CHANGELOG +## v0.21.1 + +Namada 0.21.0 is a patch release addressing some minor changes to the PGF and IBC components. + +### BUG FIXES + +- Introduce a new genesis section to control PGF storage at chain start. + ([\#1816](https://github.com/anoma/namada/pull/1816)) + +### FEATURES + +- Support the memo field of IBC transfer + ([\#1635](https://github.com/anoma/namada/issues/1635)) + +## v0.21.0 + +Namada 0.21.0 is a minor release introducing a first version of the PGF mechanism, addressing several +improvements to the PoS and Governance system and some changes to the ledger stability. + +### BUG FIXES + +- Fixes buggy Display for the Dec type when the number is some multiple of 10 + ([\#1774](https://github.com/anoma/namada/pull/1774)) +- Downgraded sysinfo back to v0.27.8 with a working available memory report on + Mac M1. ([\#1775](https://github.com/anoma/namada/pull/1775)) +- Fixes buggy error handling in pos unjail_validator. Now properly enforces that + if an unjail tx is submitted when the validator state is something other than + Jailed in any of the current or future epochs, the tx will error out and fail. + ([\#1793](https://github.com/anoma/namada/pull/1793)) +- Fix available_memory size + ([\#1801](https://github.com/anoma/namada/issues/1801)) + +### FEATURES + +- Introduce multisignature accounts and transaction format. It is now possible + to supply multiple public keys when creating a new account/validator and + specify the minimum number of signatures required to authorize a transaction. + ([\#1765](https://github.com/anoma/namada/pull/1765)) +- Introduce a simplified version of Public Good Fundings. + ([\#1803](https://github.com/anoma/namada/pull/1803)) + +### TESTING + +- Added pre-built MASP proofs for integration tests. + ([\#1768](https://github.com/anoma/namada/pull/1768)) + ## v0.20.1 Namada 0.20.1 is a patch release addressing a bug in the inflation mechanism and minor ledger improvements. diff --git a/Cargo.lock b/Cargo.lock index decc428928..3a069b0956 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -352,22 +352,6 @@ dependencies = [ "syn 2.0.15", ] -[[package]] -name = "async-tungstenite" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e00550829ef8e2c4115250d0ee43305649b0fa95f78a32ce5b07da0b73d95c5c" -dependencies = [ - "futures-io", - "futures-util", - "log", - "pin-project-lite", - "tokio", - "tokio-rustls 0.22.0", - "tungstenite 0.12.0", - "webpki-roots 0.21.1", -] - [[package]] name = "async_io_stream" version = "0.3.3" @@ -457,12 +441,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - [[package]] name = "base16ct" version = "0.2.0" @@ -511,12 +489,6 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf9ff0bbfd639f15c74af777d81383cf53efb7c93613f6cab67c6c11e05bbf8b" -[[package]] -name = "bech32" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" - [[package]] name = "bellman" version = "0.13.1" @@ -606,27 +578,6 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" -[[package]] -name = "bitcoin" -version = "0.29.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0694ea59225b0c5f3cb405ff3f670e4828358ed26aec49dc352f730f0cb1a8a3" -dependencies = [ - "bech32 0.9.1", - "bitcoin_hashes", - "secp256k1", - "serde 1.0.163", -] - -[[package]] -name = "bitcoin_hashes" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" -dependencies = [ - "serde 1.0.163", -] - [[package]] name = "bitflags" version = "1.2.1" @@ -789,7 +740,17 @@ name = "borsh" version = "0.9.4" source = "git+https://github.com/heliaxdev/borsh-rs.git?rev=cd5223e5103c4f139e0c54cf8259b7ec5ec4073a#cd5223e5103c4f139e0c54cf8259b7ec5ec4073a" dependencies = [ - "borsh-derive", + "borsh-derive 0.9.4", + "hashbrown 0.11.2", +] + +[[package]] +name = "borsh" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +dependencies = [ + "borsh-derive 0.10.3", "hashbrown 0.11.2", ] @@ -798,8 +759,21 @@ name = "borsh-derive" version = "0.9.4" source = "git+https://github.com/heliaxdev/borsh-rs.git?rev=cd5223e5103c4f139e0c54cf8259b7ec5ec4073a#cd5223e5103c4f139e0c54cf8259b7ec5ec4073a" dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", + "borsh-derive-internal 0.9.4", + "borsh-schema-derive-internal 0.9.4", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" +dependencies = [ + "borsh-derive-internal 0.10.3", + "borsh-schema-derive-internal 0.10.3", "proc-macro-crate 0.1.5", "proc-macro2", "syn 1.0.109", @@ -815,6 +789,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "borsh-derive-internal" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "borsh-schema-derive-internal" version = "0.9.4" @@ -825,6 +810,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "bs58" version = "0.4.0" @@ -895,12 +891,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "bytecount" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c" - [[package]] name = "byteorder" version = "1.4.3" @@ -945,19 +935,6 @@ dependencies = [ "serde 1.0.163", ] -[[package]] -name = "cargo_metadata" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" -dependencies = [ - "camino", - "cargo-platform", - "semver 1.0.17", - "serde 1.0.163", - "serde_json", -] - [[package]] name = "cargo_metadata" version = "0.15.4" @@ -1140,7 +1117,7 @@ dependencies = [ "digest 0.10.6", "getrandom 0.2.9", "hmac 0.12.1", - "k256 0.13.1", + "k256", "lazy_static", "serde 1.0.163", "sha2 0.10.6", @@ -1451,18 +1428,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -[[package]] -name = "crypto-bigint" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" -dependencies = [ - "generic-array 0.14.7", - "rand_core 0.6.4", - "subtle 2.4.1", - "zeroize", -] - [[package]] name = "crypto-bigint" version = "0.5.2" @@ -1621,15 +1586,6 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" -[[package]] -name = "der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid", -] - [[package]] name = "der" version = "0.7.7" @@ -1719,16 +1675,6 @@ dependencies = [ "dirs-sys", ] -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if 1.0.0", - "dirs-sys-next", -] - [[package]] name = "dirs-sys" version = "0.3.7" @@ -1740,17 +1686,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - [[package]] name = "displaydoc" version = "0.2.4" @@ -1812,28 +1747,16 @@ dependencies = [ "memmap2", ] -[[package]] -name = "ecdsa" -version = "0.14.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" -dependencies = [ - "der 0.6.1", - "elliptic-curve 0.12.3", - "rfc6979 0.3.1", - "signature 1.6.4", -] - [[package]] name = "ecdsa" version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428" dependencies = [ - "der 0.7.7", + "der", "digest 0.10.6", - "elliptic-curve 0.13.5", - "rfc6979 0.4.0", + "elliptic-curve", + "rfc6979", "signature 2.1.0", "spki", ] @@ -1879,58 +1802,27 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ed25519-dalek-bip32" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d2be62a4061b872c8c0873ee4fc6f101ce7b889d039f019c5fa2af471a59908" -dependencies = [ - "derivation-path", - "ed25519-dalek", - "hmac 0.12.1", - "sha2 0.10.6", -] - [[package]] name = "either" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" -[[package]] -name = "elliptic-curve" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" -dependencies = [ - "base16ct 0.1.1", - "crypto-bigint 0.4.9", - "der 0.6.1", - "digest 0.10.6", - "ff 0.12.1", - "generic-array 0.14.7", - "group 0.12.1", - "rand_core 0.6.4", - "sec1 0.3.0", - "subtle 2.4.1", - "zeroize", -] - [[package]] name = "elliptic-curve" version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" dependencies = [ - "base16ct 0.2.0", - "crypto-bigint 0.5.2", + "base16ct", + "crypto-bigint", "digest 0.10.6", "ff 0.13.0", "generic-array 0.14.7", "group 0.13.0", "pkcs8", "rand_core 0.6.4", - "sec1 0.7.2", + "sec1", "subtle 2.4.1", "zeroize", ] @@ -1953,7 +1845,7 @@ dependencies = [ "base64 0.13.1", "bytes", "hex", - "k256 0.13.1", + "k256", "log", "rand 0.8.5", "rlp", @@ -2039,15 +1931,6 @@ dependencies = [ "libc", ] -[[package]] -name = "error-chain" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" -dependencies = [ - "version_check", -] - [[package]] name = "escargot" version = "0.5.7" @@ -2287,13 +2170,13 @@ checksum = "6da5fa198af0d3be20c19192df2bd9590b92ce09a8421e793bec8851270f1b05" dependencies = [ "arrayvec 0.7.2", "bytes", - "cargo_metadata 0.15.4", + "cargo_metadata", "chrono", - "elliptic-curve 0.13.5", + "elliptic-curve", "ethabi", "generic-array 0.14.7", "hex", - "k256 0.13.1", + "k256", "num_enum", "once_cell", "open-fastrlp", @@ -2395,7 +2278,7 @@ dependencies = [ "async-trait", "coins-bip32", "coins-bip39", - "elliptic-curve 0.13.5", + "elliptic-curve", "eth-keystore", "ethers-core", "hex", @@ -2475,7 +2358,7 @@ dependencies = [ "bincode", "blake2", "blake2b_simd", - "borsh", + "borsh 0.9.4", "digest 0.10.6", "ed25519-dalek", "either", @@ -2986,15 +2869,6 @@ dependencies = [ "fxhash", ] -[[package]] -name = "hdpath" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfa5bc9db2c17d2660f53ce217b778d06d68de13d1cd01c0f4e5de4b7918935f" -dependencies = [ - "byteorder", -] - [[package]] name = "hdrhistogram" version = "7.5.2" @@ -3158,22 +3032,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "humantime-serde" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c" -dependencies = [ - "humantime", - "serde 1.0.163", -] - [[package]] name = "hyper" version = "0.14.26" @@ -3210,9 +3068,9 @@ dependencies = [ "http", "hyper", "hyper-rustls", - "rustls-native-certs 0.5.0", + "rustls-native-certs", "tokio", - "tokio-rustls 0.22.0", + "tokio-rustls", "tower-service", "webpki 0.21.4", ] @@ -3228,9 +3086,9 @@ dependencies = [ "hyper", "log", "rustls 0.19.1", - "rustls-native-certs 0.5.0", + "rustls-native-certs", "tokio", - "tokio-rustls 0.22.0", + "tokio-rustls", "webpki 0.21.4", "webpki-roots 0.21.1", ] @@ -3285,8 +3143,8 @@ dependencies = [ [[package]] name = "ibc" -version = "0.36.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs.git?rev=634f4ede136d045dd6f1ff8f4984dd0006aa15f0#634f4ede136d045dd6f1ff8f4984dd0006aa15f0" +version = "0.41.0" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs.git?rev=38a827d3901e590b2935ee5b6b81b4d67c399560#38a827d3901e590b2935ee5b6b81b4d67c399560" dependencies = [ "bytes", "cfg-if 1.0.0", @@ -3317,106 +3175,19 @@ dependencies = [ [[package]] name = "ibc-proto" -version = "0.26.0" -source = "git+https://github.com/heliaxdev/ibc-proto-rs.git?rev=bb16e17a4d9260d5f20516a8eda43fa52377fad2#bb16e17a4d9260d5f20516a8eda43fa52377fad2" -dependencies = [ - "base64 0.13.1", - "bytes", - "flex-error", - "prost", - "serde 1.0.163", - "subtle-encoding", - "tendermint-proto", - "tonic", -] - -[[package]] -name = "ibc-relayer" -version = "0.22.0" -source = "git+https://github.com/heliaxdev/hermes.git?rev=fea6928dace1af3e38c5b223f933c1d07720811d#fea6928dace1af3e38c5b223f933c1d07720811d" -dependencies = [ - "anyhow", - "async-stream", - "bech32 0.9.1", - "bitcoin", - "bs58", - "bytes", - "crossbeam-channel 0.5.8", - "digest 0.10.6", - "dirs-next", - "ed25519", - "ed25519-dalek", - "ed25519-dalek-bip32", - "flex-error", - "futures", - "generic-array 0.14.7", - "hdpath", - "hex", - "http", - "humantime", - "humantime-serde", - "ibc-proto", - "ibc-relayer-types", - "itertools", - "moka", - "num-bigint 0.4.3", - "num-rational 0.4.1", - "prost", - "regex", - "retry", - "ripemd", - "secp256k1", - "semver 1.0.17", - "serde 1.0.163", - "serde_derive", - "serde_json", - "sha2 0.10.6", - "signature 1.6.4", - "strum", - "subtle-encoding", - "tendermint", - "tendermint-light-client", - "tendermint-light-client-verifier", - "tendermint-proto", - "tendermint-rpc", - "thiserror", - "tiny-bip39 1.0.0", - "tiny-keccak", - "tokio", - "toml 0.5.9", - "tonic", - "tracing 0.1.37", - "uuid 1.3.2", -] - -[[package]] -name = "ibc-relayer-types" -version = "0.22.0" -source = "git+https://github.com/heliaxdev/hermes.git?rev=fea6928dace1af3e38c5b223f933c1d07720811d#fea6928dace1af3e38c5b223f933c1d07720811d" +version = "0.30.0" +source = "git+https://github.com/heliaxdev/ibc-proto-rs.git?rev=31892ee743b2af017d5629b2af419ee20b6100c7#31892ee743b2af017d5629b2af419ee20b6100c7" dependencies = [ + "base64 0.21.0", + "borsh 0.10.3", "bytes", - "derive_more", - "dyn-clone", - "erased-serde", "flex-error", - "ibc-proto", - "ics23", - "itertools", - "num-rational 0.4.1", - "primitive-types", + "parity-scale-codec", "prost", - "safe-regex", + "scale-info", "serde 1.0.163", - "serde_derive", - "serde_json", "subtle-encoding", - "tendermint", - "tendermint-light-client-verifier", "tendermint-proto", - "tendermint-rpc", - "tendermint-testgen", - "time", - "uint", ] [[package]] @@ -3519,7 +3290,7 @@ name = "index-set" version = "0.7.1" source = "git+https://github.com/heliaxdev/index-set?tag=v0.7.1#dc24cdbbe3664514d59f1a4c4031863fc565f1c2" dependencies = [ - "borsh", + "borsh 0.9.4", "serde 1.0.163", ] @@ -3553,15 +3324,6 @@ dependencies = [ "generic-array 0.14.7", ] -[[package]] -name = "input_buffer" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f97967975f448f1a7ddb12b0bc41069d09ed6a1c161a92687e057325db35d413" -dependencies = [ - "bytes", -] - [[package]] name = "instant" version = "0.1.12" @@ -3659,18 +3421,6 @@ dependencies = [ "subtle 2.4.1", ] -[[package]] -name = "k256" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" -dependencies = [ - "cfg-if 1.0.0", - "ecdsa 0.14.8", - "elliptic-curve 0.12.3", - "sha2 0.10.6", -] - [[package]] name = "k256" version = "0.13.1" @@ -3678,8 +3428,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" dependencies = [ "cfg-if 1.0.0", - "ecdsa 0.16.7", - "elliptic-curve 0.13.5", + "ecdsa", + "elliptic-curve", "once_cell", "sha2 0.10.6", "signature 2.1.0", @@ -3930,15 +3680,6 @@ dependencies = [ "libc", ] -[[package]] -name = "mach2" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" -dependencies = [ - "libc", -] - [[package]] name = "madato" version = "0.5.3" @@ -3958,7 +3699,7 @@ name = "masp_note_encryption" version = "0.2.0" source = "git+https://github.com/anoma/masp?rev=252a6059565b125c1444e9e7d0b7c8da0fba8f8f#252a6059565b125c1444e9e7d0b7c8da0fba8f8f" dependencies = [ - "borsh", + "borsh 0.9.4", "chacha20 0.9.1", "chacha20poly1305", "cipher 0.4.4", @@ -3977,7 +3718,7 @@ dependencies = [ "blake2b_simd", "blake2s_simd", "bls12_381", - "borsh", + "borsh 0.9.4", "byteorder", "ff 0.12.1", "fpe", @@ -4186,29 +3927,6 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94c7128ba23c81f6471141b90f17654f89ef44a56e14b8a4dd0fddfccd655277" -[[package]] -name = "moka" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ca9b167ed904bc89a2f64c4be5014615c26fd9c4ddd2042c6094744c7df11a" -dependencies = [ - "crossbeam-channel 0.5.8", - "crossbeam-epoch", - "crossbeam-utils 0.8.15", - "num_cpus", - "once_cell", - "parking_lot", - "quanta", - "rustc_version 0.4.0", - "scheduled-thread-pool", - "skeptic", - "smallvec", - "tagptr", - "thiserror", - "triomphe", - "uuid 1.3.2", -] - [[package]] name = "more-asserts" version = "0.2.2" @@ -4241,13 +3959,13 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "namada" -version = "0.20.1" +version = "0.21.1" dependencies = [ "assert_matches", "async-trait", "base58 0.2.0", "bimap", - "borsh", + "borsh 0.9.4", "byte-unit", "circular-queue", "clru", @@ -4289,7 +4007,7 @@ dependencies = [ "tendermint-rpc", "test-log", "thiserror", - "tiny-bip39 0.8.2", + "tiny-bip39", "tiny-hderive", "tokio", "toml 0.5.9", @@ -4309,7 +4027,7 @@ dependencies = [ [[package]] name = "namada_apps" -version = "0.20.1" +version = "0.21.1" dependencies = [ "ark-serialize", "ark-std", @@ -4320,7 +4038,7 @@ dependencies = [ "bimap", "bit-set", "blake2b-rs", - "borsh", + "borsh 0.9.4", "byte-unit", "byteorder", "bytes", @@ -4398,14 +4116,14 @@ dependencies = [ [[package]] name = "namada_core" -version = "0.20.1" +version = "0.21.1" dependencies = [ "ark-bls12-381", "ark-ec", "ark-serialize", "assert_matches", "bech32 0.8.1", - "borsh", + "borsh 0.9.4", "chrono", "data-encoding", "derivative", @@ -4455,9 +4173,9 @@ dependencies = [ [[package]] name = "namada_encoding_spec" -version = "0.20.1" +version = "0.21.1" dependencies = [ - "borsh", + "borsh 0.9.4", "itertools", "lazy_static", "madato", @@ -4466,10 +4184,10 @@ dependencies = [ [[package]] name = "namada_ethereum_bridge" -version = "0.20.1" +version = "0.21.1" dependencies = [ "assert_matches", - "borsh", + "borsh 0.9.4", "data-encoding", "ethabi", "ethers", @@ -4490,7 +4208,7 @@ dependencies = [ [[package]] name = "namada_macros" -version = "0.20.1" +version = "0.21.1" dependencies = [ "proc-macro2", "quote", @@ -4499,9 +4217,9 @@ dependencies = [ [[package]] name = "namada_proof_of_stake" -version = "0.20.1" +version = "0.21.1" dependencies = [ - "borsh", + "borsh 0.9.4", "data-encoding", "derivative", "itertools", @@ -4517,20 +4235,20 @@ dependencies = [ [[package]] name = "namada_test_utils" -version = "0.20.1" +version = "0.21.1" dependencies = [ - "borsh", + "borsh 0.9.4", "namada_core", "strum", ] [[package]] name = "namada_tests" -version = "0.20.1" +version = "0.21.1" dependencies = [ "assert_cmd", "async-trait", - "borsh", + "borsh 0.9.4", "chrono", "clap", "color-eyre", @@ -4543,8 +4261,6 @@ dependencies = [ "file-serve", "fs_extra", "hyper", - "ibc-relayer", - "ibc-relayer-types", "itertools", "lazy_static", "namada", @@ -4561,9 +4277,11 @@ dependencies = [ "prost", "rand 0.8.5", "regex", + "serde 1.0.163", "serde_json", "sha2 0.9.9", "tempfile", + "tendermint-light-client", "test-log", "tokio", "toml 0.5.9", @@ -4573,9 +4291,9 @@ dependencies = [ [[package]] name = "namada_tx_prelude" -version = "0.20.1" +version = "0.21.1" dependencies = [ - "borsh", + "borsh 0.9.4", "masp_primitives", "namada_core", "namada_macros", @@ -4587,18 +4305,18 @@ dependencies = [ [[package]] name = "namada_vm_env" -version = "0.20.1" +version = "0.21.1" dependencies = [ - "borsh", + "borsh 0.9.4", "masp_primitives", "namada_core", ] [[package]] name = "namada_vp_prelude" -version = "0.20.1" +version = "0.21.1" dependencies = [ - "borsh", + "borsh 0.9.4", "namada_core", "namada_macros", "namada_proof_of_stake", @@ -4733,7 +4451,6 @@ dependencies = [ "autocfg", "num-integer", "num-traits 0.2.15", - "serde 1.0.163", ] [[package]] @@ -4809,7 +4526,6 @@ dependencies = [ "num-bigint 0.4.3", "num-integer", "num-traits 0.2.15", - "serde 1.0.163", ] [[package]] @@ -5260,7 +4976,7 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der 0.7.7", + "der", "spki", ] @@ -5524,33 +5240,6 @@ dependencies = [ "nix", ] -[[package]] -name = "pulldown-cmark" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6" -dependencies = [ - "bitflags 1.2.1", - "memchr", - "unicase", -] - -[[package]] -name = "quanta" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" -dependencies = [ - "crossbeam-utils 0.8.15", - "libc", - "mach2", - "once_cell", - "raw-cpuid", - "wasi 0.11.0+wasi-snapshot-preview1", - "web-sys", - "winapi", -] - [[package]] name = "quick-error" version = "1.2.3" @@ -5658,15 +5347,6 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "raw-cpuid" -version = "10.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" -dependencies = [ - "bitflags 1.2.1", -] - [[package]] name = "rayon" version = "1.5.3" @@ -5837,23 +5517,6 @@ dependencies = [ "winreg", ] -[[package]] -name = "retry" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9166d72162de3575f950507683fac47e30f6f2c3836b71b7fbc61aa517c9c5f4" - -[[package]] -name = "rfc6979" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" -dependencies = [ - "crypto-bigint 0.4.9", - "hmac 0.12.1", - "zeroize", -] - [[package]] name = "rfc6979" version = "0.4.0" @@ -5888,17 +5551,6 @@ dependencies = [ "digest 0.10.6", ] -[[package]] -name = "ripemd160" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "opaque-debug 0.3.0", -] - [[package]] name = "rkyv" version = "0.7.42" @@ -6084,18 +5736,6 @@ dependencies = [ "security-framework", ] -[[package]] -name = "rustls-native-certs" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" -dependencies = [ - "openssl-probe", - "rustls-pemfile", - "schannel", - "security-framework", -] - [[package]] name = "rustls-pemfile" version = "1.0.3" @@ -6227,15 +5867,6 @@ dependencies = [ "windows-sys 0.42.0", ] -[[package]] -name = "scheduled-thread-pool" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" -dependencies = [ - "parking_lot", -] - [[package]] name = "scoped-tls" version = "1.0.1" @@ -6286,54 +5917,20 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" -[[package]] -name = "sec1" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" -dependencies = [ - "base16ct 0.1.1", - "der 0.6.1", - "generic-array 0.14.7", - "subtle 2.4.1", - "zeroize", -] - [[package]] name = "sec1" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0aec48e813d6b90b15f0b8948af3c63483992dee44c03e9930b3eebdabe046e" dependencies = [ - "base16ct 0.2.0", - "der 0.7.7", + "base16ct", + "der", "generic-array 0.14.7", "pkcs8", "subtle 2.4.1", "zeroize", ] -[[package]] -name = "secp256k1" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" -dependencies = [ - "bitcoin_hashes", - "rand 0.8.5", - "secp256k1-sys", - "serde 1.0.163", -] - -[[package]] -name = "secp256k1-sys" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" -dependencies = [ - "cc", -] - [[package]] name = "security-framework" version = "2.3.1" @@ -6508,19 +6105,6 @@ dependencies = [ "yaml-rust", ] -[[package]] -name = "sha-1" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.9.0", - "opaque-debug 0.3.0", -] - [[package]] name = "sha1" version = "0.10.5" @@ -6617,10 +6201,6 @@ name = "signature" version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" -dependencies = [ - "digest 0.10.6", - "rand_core 0.6.4", -] [[package]] name = "signature" @@ -6644,21 +6224,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc47a29ce97772ca5c927f75bac34866b16d64e07f330c3248e2d7226623901b" -[[package]] -name = "skeptic" -version = "0.13.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" -dependencies = [ - "bytecount", - "cargo_metadata 0.14.2", - "error-chain", - "glob", - "pulldown-cmark", - "tempfile", - "walkdir", -] - [[package]] name = "slab" version = "0.4.8" @@ -6699,7 +6264,7 @@ version = "0.3.1-pre" source = "git+https://github.com/heliaxdev/sparse-merkle-tree?rev=e086b235ed6e68929bf73f617dd61cd17b000a56#e086b235ed6e68929bf73f617dd61cd17b000a56" dependencies = [ "blake2b-rs", - "borsh", + "borsh 0.9.4", "cfg-if 1.0.0", "ics23", "sha2 0.9.9", @@ -6724,7 +6289,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" dependencies = [ "base64ct", - "der 0.7.7", + "der", ] [[package]] @@ -6837,9 +6402,9 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "sysinfo" -version = "0.29.4" +version = "0.27.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "751e810399bba86e9326f5762b7f32ac5a085542df78da6a78d94e07d14d7c11" +checksum = "a902e9050fca0a5d6877550b769abd2bd1ce8c04634b941dbe2809735e1a1e33" dependencies = [ "cfg-if 1.0.0", "core-foundation-sys", @@ -6849,12 +6414,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "tagptr" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" - [[package]] name = "tap" version = "1.0.1" @@ -6902,12 +6461,10 @@ dependencies = [ "ed25519-dalek", "flex-error", "futures", - "k256 0.11.6", "num-traits 0.2.15", "once_cell", "prost", "prost-types", - "ripemd160", "serde 1.0.163", "serde_bytes", "serde_json", @@ -6990,7 +6547,6 @@ version = "0.23.6" source = "git+https://github.com/heliaxdev/tendermint-rs.git?rev=b7d1e5afc6f2ccb3fd1545c2174bab1cc48d7fa7#b7d1e5afc6f2ccb3fd1545c2174bab1cc48d7fa7" dependencies = [ "async-trait", - "async-tungstenite", "bytes", "flex-error", "futures", @@ -7134,25 +6690,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "tiny-bip39" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62cc94d358b5a1e84a5cb9109f559aa3c4d634d2b1b4de3d0fa4adc7c78e2861" -dependencies = [ - "anyhow", - "hmac 0.12.1", - "once_cell", - "pbkdf2 0.11.0", - "rand 0.8.5", - "rustc-hash", - "sha2 0.10.6", - "thiserror", - "unicode-normalization", - "wasm-bindgen", - "zeroize", -] - [[package]] name = "tiny-hderive" version = "0.3.0" @@ -7263,17 +6800,6 @@ dependencies = [ "webpki 0.21.4", ] -[[package]] -name = "tokio-rustls" -version = "0.23.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" -dependencies = [ - "rustls 0.20.8", - "tokio", - "webpki 0.22.0", -] - [[package]] name = "tokio-stream" version = "0.1.14" @@ -7307,7 +6833,7 @@ dependencies = [ "futures-util", "log", "tokio", - "tungstenite 0.18.0", + "tungstenite", ] [[package]] @@ -7403,10 +6929,7 @@ dependencies = [ "pin-project", "prost", "prost-derive", - "rustls-native-certs 0.6.3", - "rustls-pemfile", "tokio", - "tokio-rustls 0.23.4", "tokio-stream", "tokio-util 0.7.8", "tower", @@ -7658,37 +7181,12 @@ dependencies = [ "tracing-futures 0.2.5 (git+https://github.com/tokio-rs/tracing/?tag=tracing-0.1.30)", ] -[[package]] -name = "triomphe" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee8098afad3fb0c54a9007aab6804558410503ad676d4633f9c2559a00ac0f" - [[package]] name = "try-lock" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" -[[package]] -name = "tungstenite" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ada8297e8d70872fa9a551d93250a9f407beb9f37ef86494eb20012a2ff7c24" -dependencies = [ - "base64 0.13.1", - "byteorder", - "bytes", - "http", - "httparse", - "input_buffer", - "log", - "rand 0.8.5", - "sha-1", - "url", - "utf-8", -] - [[package]] name = "tungstenite" version = "0.18.0" @@ -7840,9 +7338,6 @@ name = "uuid" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dad5567ad0cf5b760e5665964bec1b47dfd077ba8a2544b513f3556d3d239a2" -dependencies = [ - "getrandom 0.2.9", -] [[package]] name = "valuable" diff --git a/Cargo.toml b/Cargo.toml index 4019e0e50e..2d50daf0b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ members = [ exclude = [ "wasm", "wasm_for_tests", + "test_fixtures", ] [workspace.package] @@ -31,7 +32,7 @@ keywords = ["blockchain", "privacy", "crypto", "protocol", "network"] license = "GPL-3.0" readme = "README.md" repository = "https://github.com/anoma/namada" -version = "0.20.1" +version = "0.21.1" [workspace.dependencies] ark-bls12-381 = {version = "0.3"} @@ -76,8 +77,6 @@ flate2 = "1.0.22" fs_extra = "1.2.0" futures = "0.3" git2 = "0.13.25" -ibc-relayer = {git = "https://github.com/heliaxdev/hermes.git", rev = "fea6928dace1af3e38c5b223f933c1d07720811d", default-features = false} -ibc-relayer-types = {git = "https://github.com/heliaxdev/hermes.git", rev = "fea6928dace1af3e38c5b223f933c1d07720811d", default-features = false } ics23 = "0.9.0" index-set = {git = "https://github.com/heliaxdev/index-set", tag = "v0.7.1", features = ["serialize-borsh", "serialize-serde"]} itertools = "0.10.0" @@ -117,10 +116,11 @@ sha2 = "0.9.3" signal-hook = "0.3.9" slip10_ed25519 = "0.1.3" # sysinfo with disabled multithread feature -sysinfo = {version = "0.29.4", default-features = false} +sysinfo = {version = "0.27.8", default-features = false} tar = "0.4.37" tempfile = {version = "3.2.0"} tendermint-config = {git = "https://github.com/heliaxdev/tendermint-rs.git", rev = "b7d1e5afc6f2ccb3fd1545c2174bab1cc48d7fa7"} +tendermint-light-client = {git = "https://github.com/heliaxdev/tendermint-rs.git", rev = "b7d1e5afc6f2ccb3fd1545c2174bab1cc48d7fa7"} test-log = {version = "0.2.7", default-features = false, features = ["trace"]} tiny-bip39 = {git = "https://github.com/anoma/tiny-bip39.git", rev = "bf0f6d8713589b83af7a917366ec31f5275c0e57"} tiny-hderive = "0.3.0" diff --git a/Makefile b/Makefile index 638b28ceaf..0b6345a50d 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ package = namada NAMADA_E2E_USE_PREBUILT_BINARIES ?= true NAMADA_E2E_DEBUG ?= true RUST_BACKTRACE ?= 1 +NAMADA_MASP_TEST_SEED ?= 0 cargo := $(env) cargo rustup := $(env) rustup @@ -116,12 +117,14 @@ audit: test: test-unit test-e2e test-wasm -# Unit tests with coverage report test-coverage: + # Run integration tests with pre-built MASP proofs + NAMADA_MASP_TEST_SEED=$(NAMADA_MASP_TEST_SEED) \ + NAMADA_MASP_TEST_PROOFS=load \ $(cargo) +$(nightly) llvm-cov --output-dir target \ --features namada/testing \ --html \ - -- --skip e2e --skip integration -Z unstable-options --report-time + -- --skip e2e -Z unstable-options --report-time # NOTE: `TEST_FILTER` is prepended with `e2e::`. Since filters in `cargo test` # work with a substring search, TEST_FILTER only works if it contains a string @@ -137,7 +140,23 @@ test-e2e: --test-threads=1 \ -Z unstable-options --report-time +# Run integration tests with pre-built MASP proofs test-integration: + NAMADA_MASP_TEST_SEED=$(NAMADA_MASP_TEST_SEED) \ + NAMADA_MASP_TEST_PROOFS=load \ + make test-integration-slow + +# Clear pre-built proofs, run integration tests and save the new proofs +test-integration-save-proofs: + # Clear old proofs first + rm --force test_fixtures/masp_proofs/*.bin || true + NAMADA_MASP_TEST_SEED=$(NAMADA_MASP_TEST_SEED) \ + NAMADA_MASP_TEST_PROOFS=save \ + TEST_FILTER=masp \ + make test-integration-slow + +# Run integration tests without specifiying any pre-built MASP proofs option +test-integration-slow: RUST_BACKTRACE=$(RUST_BACKTRACE) \ $(cargo) +$(nightly) test integration::$(TEST_FILTER) \ -Z unstable-options \ diff --git a/README.md b/README.md index 10b2230009..39c53909ea 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## Overview -[Namada](http://namada.net) is a Proof-of-Stake L1 for interchain asset-agnostic privacy. Namada uses Tendermint BFT +[Namada](http://namada.net) is a Proof-of-Stake L1 for interchain asset-agnostic privacy. Namada uses CometBFT consensus and enables multi-asset shielded transfers for any native or non-native asset. Namada features full IBC protocol support, a natively integrated Ethereum bridge, a modern proof-of-stake @@ -27,7 +27,7 @@ interaction with the protocol. ## 💾 Installing -There is a single command to build and install Namada executables from source (the node, the client and the wallet). This command will also verify that a compatible version of [Tendermint](#dependencies) is available and if not, attempt to install it. Note that currently at least 16GB RAM is needed to build from source. +There is a single command to build and install Namada executables from source (the node, the client and the wallet). This command will also verify that a compatible version of [CometBFT](#dependencies) is available and if not, attempt to install it. Note that currently at least 16GB RAM is needed to build from source. ```shell make install @@ -72,7 +72,7 @@ To change the log level, set `NAMADA_LOG` environment variable to one of: * `debug` * `trace` -The default is set to `info` for all the modules, expect for Tendermint ABCI, which has a lot of `debug` logging. +The default is set to `info` for all the modules, expect for CombetBFT ABCI, which has a lot of `debug` logging. For more fine-grained logging levels settings, please refer to the [tracing subscriber docs](https://docs.rs/tracing-subscriber/0.2.18/tracing_subscriber/struct.EnvFilter.html#directives) for more information. @@ -84,4 +84,4 @@ Please see the [contributing page](./CONTRIBUTING.md). ### Dependencies -The ledger currently requires that the Heliax fork of tendermint[v0.1.4-abciplus] is installed and available on path. This can be achieved through following [these instructions](https://docs.namada.net/user-guide/install/installing-tendermint.html) +The ledger currently requires [CometBFT v0.37.2](https://github.com/cometbft/cometbft/releases/tag/v0.37.2) is installed and available on path. This can be achieved through following [these instructions](https://github.com/cometbft/cometbft/blob/main/docs/guides/install.md) diff --git a/apps/src/bin/namada-client/cli.rs b/apps/src/bin/namada-client/cli.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/src/bin/namada/cli.rs b/apps/src/bin/namada/cli.rs index 8c7a1e0b49..0259ba525a 100644 --- a/apps/src/bin/namada/cli.rs +++ b/apps/src/bin/namada/cli.rs @@ -47,7 +47,7 @@ fn handle_command(cmd: cli::cmds::Namada, raw_sub_cmd: String) -> Result<()> { | cli::cmds::Namada::TxCustom(_) | cli::cmds::Namada::TxTransfer(_) | cli::cmds::Namada::TxIbcTransfer(_) - | cli::cmds::Namada::TxUpdateVp(_) + | cli::cmds::Namada::TxUpdateAccount(_) | cli::cmds::Namada::TxRevealPk(_) | cli::cmds::Namada::TxInitProposal(_) | cli::cmds::Namada::TxVoteProposal(_) => { diff --git a/apps/src/lib/cli.rs b/apps/src/lib/cli.rs index 12927cca13..31b28977f3 100644 --- a/apps/src/lib/cli.rs +++ b/apps/src/lib/cli.rs @@ -58,7 +58,7 @@ pub mod cmds { TxCustom(TxCustom), TxTransfer(TxTransfer), TxIbcTransfer(TxIbcTransfer), - TxUpdateVp(TxUpdateVp), + TxUpdateAccount(TxUpdateAccount), TxInitProposal(TxInitProposal), TxVoteProposal(TxVoteProposal), TxRevealPk(TxRevealPk), @@ -75,7 +75,7 @@ pub mod cmds { .subcommand(TxCustom::def()) .subcommand(TxTransfer::def()) .subcommand(TxIbcTransfer::def()) - .subcommand(TxUpdateVp::def()) + .subcommand(TxUpdateAccount::def()) .subcommand(TxInitProposal::def()) .subcommand(TxVoteProposal::def()) .subcommand(TxRevealPk::def()) @@ -93,7 +93,8 @@ pub mod cmds { let tx_transfer = SubCmd::parse(matches).map(Self::TxTransfer); let tx_ibc_transfer = SubCmd::parse(matches).map(Self::TxIbcTransfer); - let tx_update_vp = SubCmd::parse(matches).map(Self::TxUpdateVp); + let tx_update_account = + SubCmd::parse(matches).map(Self::TxUpdateAccount); let tx_init_proposal = SubCmd::parse(matches).map(Self::TxInitProposal); let tx_vote_proposal = @@ -107,7 +108,7 @@ pub mod cmds { .or(tx_custom) .or(tx_transfer) .or(tx_ibc_transfer) - .or(tx_update_vp) + .or(tx_update_account) .or(tx_init_proposal) .or(tx_vote_proposal) .or(tx_reveal_pk) @@ -214,7 +215,7 @@ pub mod cmds { .subcommand(TxCustom::def().display_order(1)) .subcommand(TxTransfer::def().display_order(1)) .subcommand(TxIbcTransfer::def().display_order(1)) - .subcommand(TxUpdateVp::def().display_order(1)) + .subcommand(TxUpdateAccount::def().display_order(1)) .subcommand(TxInitAccount::def().display_order(1)) .subcommand(TxRevealPk::def().display_order(1)) // Proposal transactions @@ -231,6 +232,7 @@ pub mod cmds { .subcommand(AddToEthBridgePool::def().display_order(3)) // Queries .subcommand(QueryEpoch::def().display_order(4)) + .subcommand(QueryAccount::def().display_order(4)) .subcommand(QueryTransfers::def().display_order(4)) .subcommand(QueryConversions::def().display_order(4)) .subcommand(QueryBlock::def().display_order(4)) @@ -245,9 +247,12 @@ pub mod cmds { .subcommand(QueryProposal::def().display_order(4)) .subcommand(QueryProposalResult::def().display_order(4)) .subcommand(QueryProtocolParameters::def().display_order(4)) + .subcommand(QueryPgf::def().display_order(4)) .subcommand(QueryValidatorState::def().display_order(4)) + // Actions + .subcommand(SignTx::def().display_order(5)) // Utils - .subcommand(Utils::def().display_order(5)) + .subcommand(Utils::def().display_order(6)) } fn parse(matches: &ArgMatches) -> Option { @@ -255,7 +260,8 @@ pub mod cmds { let tx_custom = Self::parse_with_ctx(matches, TxCustom); let tx_transfer = Self::parse_with_ctx(matches, TxTransfer); let tx_ibc_transfer = Self::parse_with_ctx(matches, TxIbcTransfer); - let tx_update_vp = Self::parse_with_ctx(matches, TxUpdateVp); + let tx_update_account = + Self::parse_with_ctx(matches, TxUpdateAccount); let tx_init_account = Self::parse_with_ctx(matches, TxInitAccount); let tx_init_validator = Self::parse_with_ctx(matches, TxInitValidator); @@ -272,6 +278,7 @@ pub mod cmds { let unbond = Self::parse_with_ctx(matches, Unbond); let withdraw = Self::parse_with_ctx(matches, Withdraw); let query_epoch = Self::parse_with_ctx(matches, QueryEpoch); + let query_account = Self::parse_with_ctx(matches, QueryAccount); let query_transfers = Self::parse_with_ctx(matches, QueryTransfers); let query_conversions = Self::parse_with_ctx(matches, QueryConversions); @@ -292,15 +299,17 @@ pub mod cmds { Self::parse_with_ctx(matches, QueryProposalResult); let query_protocol_parameters = Self::parse_with_ctx(matches, QueryProtocolParameters); + let query_pgf = Self::parse_with_ctx(matches, QueryPgf); let query_validator_state = Self::parse_with_ctx(matches, QueryValidatorState); let add_to_eth_bridge_pool = Self::parse_with_ctx(matches, AddToEthBridgePool); + let sign_tx = Self::parse_with_ctx(matches, SignTx); let utils = SubCmd::parse(matches).map(Self::WithoutContext); tx_custom .or(tx_transfer) .or(tx_ibc_transfer) - .or(tx_update_vp) + .or(tx_update_account) .or(tx_init_account) .or(tx_reveal_pk) .or(tx_init_proposal) @@ -327,7 +336,10 @@ pub mod cmds { .or(query_proposal) .or(query_proposal_result) .or(query_protocol_parameters) + .or(query_pgf) .or(query_validator_state) + .or(query_account) + .or(sign_tx) .or(utils) } } @@ -369,7 +381,7 @@ pub mod cmds { TxTransfer(TxTransfer), TxIbcTransfer(TxIbcTransfer), QueryResult(QueryResult), - TxUpdateVp(TxUpdateVp), + TxUpdateAccount(TxUpdateAccount), TxInitAccount(TxInitAccount), TxInitValidator(TxInitValidator), TxCommissionRateChange(TxCommissionRateChange), @@ -382,6 +394,7 @@ pub mod cmds { Withdraw(Withdraw), AddToEthBridgePool(AddToEthBridgePool), QueryEpoch(QueryEpoch), + QueryAccount(QueryAccount), QueryTransfers(QueryTransfers), QueryConversions(QueryConversions), QueryBlock(QueryBlock), @@ -396,7 +409,9 @@ pub mod cmds { QueryProposal(QueryProposal), QueryProposalResult(QueryProposalResult), QueryProtocolParameters(QueryProtocolParameters), + QueryPgf(QueryPgf), QueryValidatorState(QueryValidatorState), + SignTx(SignTx), } #[allow(clippy::large_enum_variant)] @@ -1175,6 +1190,28 @@ pub mod cmds { } } + #[derive(Clone, Debug)] + pub struct QueryPgf(pub args::QueryPgf); + + impl SubCmd for QueryPgf { + const CMD: &'static str = "query-pgf"; + + fn parse(matches: &ArgMatches) -> Option + where + Self: Sized, + { + matches + .subcommand_matches(Self::CMD) + .map(|matches| QueryPgf(args::QueryPgf::parse(matches))) + } + + fn def() -> App { + App::new(Self::CMD) + .about("Query pgf stewards and continous funding.") + .add_args::>() + } + } + #[derive(Clone, Debug)] pub struct TxCustom(pub args::TxCustom); @@ -1233,15 +1270,15 @@ pub mod cmds { } #[derive(Clone, Debug)] - pub struct TxUpdateVp(pub args::TxUpdateVp); + pub struct TxUpdateAccount(pub args::TxUpdateAccount); - impl SubCmd for TxUpdateVp { - const CMD: &'static str = "update"; + impl SubCmd for TxUpdateAccount { + const CMD: &'static str = "update-account"; fn parse(matches: &ArgMatches) -> Option { - matches - .subcommand_matches(Self::CMD) - .map(|matches| TxUpdateVp(args::TxUpdateVp::parse(matches))) + matches.subcommand_matches(Self::CMD).map(|matches| { + TxUpdateAccount(args::TxUpdateAccount::parse(matches)) + }) } fn def() -> App { @@ -1250,7 +1287,7 @@ pub mod cmds { "Send a signed transaction to update account's validity \ predicate.", ) - .add_args::>() + .add_args::>() } } @@ -1395,6 +1432,28 @@ pub mod cmds { } } + #[derive(Clone, Debug)] + pub struct QueryAccount(pub args::QueryAccount); + + impl SubCmd for QueryAccount { + const CMD: &'static str = "query-account"; + + fn parse(matches: &ArgMatches) -> Option { + matches + .subcommand_matches(Self::CMD) + .map(|matches| QueryAccount(args::QueryAccount::parse(matches))) + } + + fn def() -> App { + App::new(Self::CMD) + .about( + "Query the substorage space of a specific enstablished \ + address.", + ) + .add_args::>() + } + } + #[derive(Clone, Debug)] pub struct QueryConversions(pub args::QueryConversions); @@ -1490,6 +1549,25 @@ pub mod cmds { } } + #[derive(Clone, Debug)] + pub struct SignTx(pub args::SignTx); + + impl SubCmd for SignTx { + const CMD: &'static str = "sign-tx"; + + fn parse(matches: &ArgMatches) -> Option { + matches + .subcommand_matches(Self::CMD) + .map(|matches| SignTx(args::SignTx::parse(matches))) + } + + fn def() -> App { + App::new(Self::CMD) + .about("Query PoS bonded stake.") + .add_args::>() + } + } + #[derive(Clone, Debug)] pub struct QueryValidatorState( pub args::QueryValidatorState, @@ -2317,6 +2395,7 @@ pub mod args { pub const TX_INIT_PROPOSAL: &str = "tx_init_proposal.wasm"; pub const TX_INIT_VALIDATOR_WASM: &str = "tx_init_validator.wasm"; pub const TX_REVEAL_PK: &str = "tx_reveal_pk.wasm"; + pub const TX_UPDATE_ACCOUNT_WASM: &str = "tx_update_account.wasm"; pub const TX_TRANSFER_WASM: &str = "tx_transfer.wasm"; pub const TX_UNBOND_WASM: &str = "tx_unbond.wasm"; pub const TX_UNJAIL_VALIDATOR_WASM: &str = "tx_unjail_validator.wasm"; @@ -2379,15 +2458,8 @@ pub mod args { ); pub const ETH_SYNC: ArgFlag = flag("sync"); pub const EXPIRATION_OPT: ArgOpt = arg_opt("expiration"); - pub const FEE_AMOUNT: ArgDefault = arg_default( - "fee-amount", - DefaultFn(|| token::DenominatedAmount { - amount: token::Amount::default(), - denom: NATIVE_MAX_DECIMAL_PLACES.into(), - }), - ); - pub const FEE_PAYER: Arg = arg("fee-payer"); pub const FORCE: ArgFlag = flag("force"); + pub const GAS_PAYER: ArgOpt = arg("gas-payer").opt(); pub const GAS_AMOUNT: ArgDefault = arg_default( "gas-amount", DefaultFn(|| token::DenominatedAmount { @@ -2404,6 +2476,14 @@ pub mod args { ); pub const GAS_TOKEN: ArgDefaultFromCtx = arg_default_from_ctx("gas-token", DefaultFn(|| "NAM".parse().unwrap())); + pub const FEE_PAYER: Arg = arg("fee-payer"); + pub const FEE_AMOUNT: ArgDefault = arg_default( + "fee-amount", + DefaultFn(|| token::DenominatedAmount { + amount: token::Amount::default(), + denom: NATIVE_MAX_DECIMAL_PLACES.into(), + }), + ); pub const GENESIS_PATH: Arg = arg("genesis-path"); pub const GENESIS_VALIDATOR: ArgOpt = arg("genesis-validator").opt(); @@ -2413,6 +2493,7 @@ pub mod args { pub const HD_WALLET_DERIVATION_PATH_OPT: ArgOpt = HD_WALLET_DERIVATION_PATH.opt(); pub const HISTORIC: ArgFlag = flag("historic"); + pub const IBC_TRANSFER_MEMO: ArgOpt = arg_opt("memo"); pub const LEDGER_ADDRESS_ABOUT: &str = "Address of a ledger node as \"{scheme}://{host}:{port}\". If the \ scheme is not supplied, it is assumed to be TCP."; @@ -2434,6 +2515,8 @@ pub mod args { pub const NAMADA_START_TIME: ArgOpt = arg_opt("time"); pub const NO_CONVERSIONS: ArgFlag = flag("no-conversions"); pub const OUT_FILE_PATH_OPT: ArgOpt = arg_opt("out-file-path"); + pub const OUTPUT_FOLDER_PATH: ArgOpt = + arg_opt("output-folder-path"); pub const OWNER: Arg = arg("owner"); pub const OWNER_OPT: ArgOpt = OWNER.opt(); pub const PIN: ArgFlag = flag("pin"); @@ -2441,10 +2524,14 @@ pub mod args { "port-id", DefaultFn(|| PortId::from_str("transfer").unwrap()), ); + pub const PROPOSAL_ETH: ArgFlag = flag("eth"); + pub const PROPOSAL_PGF_STEWARD: ArgFlag = flag("pgf-stewards"); + pub const PROPOSAL_PGF_FUNDING: ArgFlag = flag("pgf-funding"); pub const PROPOSAL_OFFLINE: ArgFlag = flag("offline"); pub const PROTOCOL_KEY: ArgOpt = arg_opt("protocol-key"); pub const PRE_GENESIS_PATH: ArgOpt = arg_opt("pre-genesis-path"); pub const PUBLIC_KEY: Arg = arg("public-key"); + pub const PUBLIC_KEYS: ArgMulti = arg_multi("public-keys"); pub const PROPOSAL_ID: Arg = arg("proposal-id"); pub const PROPOSAL_ID_OPT: ArgOpt = arg_opt("proposal-id"); pub const PROPOSAL_VOTE_PGF_OPT: ArgOpt = arg_opt("pgf"); @@ -2460,9 +2547,8 @@ pub mod args { pub const SAFE_MODE: ArgFlag = flag("safe-mode"); pub const SCHEME: ArgDefault = arg_default("scheme", DefaultFn(|| SchemeType::Ed25519)); - pub const SIGNER: ArgOpt = arg_opt("signer"); - pub const SIGNING_KEY_OPT: ArgOpt = SIGNING_KEY.opt(); - pub const SIGNING_KEY: Arg = arg("signing-key"); + pub const SIGNING_KEYS: ArgMulti = arg_multi("signing-keys"); + pub const SIGNATURES: ArgMulti = arg_multi("signatures"); pub const SOURCE: Arg = arg("source"); pub const SOURCE_OPT: ArgOpt = SOURCE.opt(); pub const STORAGE_KEY: Arg = arg("storage-key"); @@ -2475,16 +2561,19 @@ pub mod args { pub const TRANSFER_SOURCE: Arg = arg("source"); pub const TRANSFER_TARGET: Arg = arg("target"); pub const TX_HASH: Arg = arg("tx-hash"); + pub const THRESOLD: ArgOpt = arg_opt("threshold"); pub const UNSAFE_DONT_ENCRYPT: ArgFlag = flag("unsafe-dont-encrypt"); pub const UNSAFE_SHOW_SECRET: ArgFlag = flag("unsafe-show-secret"); pub const VALIDATOR: Arg = arg("validator"); pub const VALIDATOR_OPT: ArgOpt = VALIDATOR.opt(); pub const VALIDATOR_ACCOUNT_KEY: ArgOpt = arg_opt("account-key"); - pub const VALIDATOR_CODE_PATH: ArgOpt = - arg_opt("validator-code-path"); + pub const VALIDATOR_ACCOUNT_KEYS: ArgMulti = + arg_multi("account-keys"); pub const VALIDATOR_CONSENSUS_KEY: ArgOpt = arg_opt("consensus-key"); + pub const VALIDATOR_CODE_PATH: ArgOpt = + arg_opt("validator-code-path"); pub const VALIDATOR_ETH_COLD_KEY: ArgOpt = arg_opt("eth-cold-key"); pub const VALIDATOR_ETH_HOT_KEY: ArgOpt = @@ -2496,6 +2585,8 @@ pub mod args { pub const WALLET_ALIAS_FORCE: ArgFlag = flag("wallet-alias-force"); pub const WASM_CHECKSUMS_PATH: Arg = arg("wasm-checksums-path"); pub const WASM_DIR: ArgOpt = arg_opt("wasm-dir"); + pub const TX_PATH: Arg = arg("tx-path"); + pub const TX_PATH_OPT: ArgOpt = TX_PATH.opt(); /// Global command arguments #[derive(Clone, Debug)] @@ -2702,9 +2793,9 @@ pub mod args { recipient: self.recipient, sender: ctx.get(&self.sender), amount: self.amount, - gas_amount: self.gas_amount, - gas_payer: ctx.get(&self.gas_payer), - code_path: ctx.read_wasm(self.code_path), + fee_amount: self.fee_amount, + fee_payer: ctx.get(&self.fee_payer), + code_path: self.code_path, } } } @@ -2716,8 +2807,8 @@ pub mod args { let recipient = ETH_ADDRESS.parse(matches); let sender = ADDRESS.parse(matches); let amount = InputAmount::Unvalidated(AMOUNT.parse(matches)); - let gas_amount = FEE_AMOUNT.parse(matches).amount; - let gas_payer = FEE_PAYER.parse(matches); + let fee_amount = FEE_AMOUNT.parse(matches).amount; + let fee_payer = FEE_PAYER.parse(matches); let code_path = PathBuf::from(TX_BRIDGE_POOL_WASM); Self { tx, @@ -2725,8 +2816,8 @@ pub mod args { recipient, sender, amount, - gas_amount, - gas_payer, + fee_amount, + fee_payer, code_path, } } @@ -3110,11 +3201,15 @@ pub mod args { fn to_sdk(self, ctx: &mut Context) -> TxCustom { TxCustom:: { tx: self.tx.to_sdk(ctx), - code_path: ctx.read_wasm(self.code_path), + code_path: self.code_path, data_path: self.data_path.map(|data_path| { std::fs::read(data_path) - .expect("Expected a file at given data path") + .expect("Expected a file at given path") }), + serialized_tx: self.serialized_tx.map(|path| { + std::fs::read(path).expect("Expected a file at given path") + }), + owner: ctx.get(&self.owner), } } } @@ -3122,26 +3217,50 @@ pub mod args { impl Args for TxCustom { fn parse(matches: &ArgMatches) -> Self { let tx = Tx::parse(matches); - let code_path = CODE_PATH.parse(matches); + let code_path = CODE_PATH_OPT.parse(matches); let data_path = DATA_PATH_OPT.parse(matches); + let serialized_tx = TX_PATH_OPT.parse(matches); + let owner = OWNER.parse(matches); Self { tx, code_path, data_path, + serialized_tx, + owner, } } fn def(app: App) -> App { app.add_args::>() .arg( - CODE_PATH + CODE_PATH_OPT .def() - .help("The path to the transaction's WASM code."), + .help("The path to the transaction's WASM code.") + .conflicts_with(TX_PATH_OPT.name), ) - .arg(DATA_PATH_OPT.def().help( - "The data file at this path containing arbitrary bytes \ - will be passed to the transaction code when it's \ - executed.", + .arg( + DATA_PATH_OPT + .def() + .help( + "The data file at this path containing arbitrary \ + bytes will be passed to the transaction code \ + when it's executed.", + ) + .requires(CODE_PATH_OPT.name) + .conflicts_with(TX_PATH_OPT.name), + ) + .arg( + TX_PATH_OPT + .def() + .help("The path to a serialized transaction.") + .conflicts_with_all([ + CODE_PATH_OPT.name, + DATA_PATH_OPT.name, + ]), + ) + .arg(OWNER.def().help( + "The address corresponding to the signatures or signing \ + keys.", )) } } @@ -3206,6 +3325,7 @@ pub mod args { channel_id: self.channel_id, timeout_height: self.timeout_height, timeout_sec_offset: self.timeout_sec_offset, + memo: self.memo, tx_code_path: self.tx_code_path.to_path_buf(), } } @@ -3222,6 +3342,7 @@ pub mod args { let channel_id = CHANNEL_ID.parse(matches); let timeout_height = TIMEOUT_HEIGHT.parse(matches); let timeout_sec_offset = TIMEOUT_SEC_OFFSET.parse(matches); + let memo = IBC_TRANSFER_MEMO.parse(matches); let tx_code_path = PathBuf::from(TX_IBC_WASM); Self { tx, @@ -3233,6 +3354,7 @@ pub mod args { channel_id, timeout_height, timeout_sec_offset, + memo, tx_code_path, } } @@ -3256,6 +3378,11 @@ pub mod args { .help("The timeout height of the destination chain."), ) .arg(TIMEOUT_SEC_OFFSET.def().help("The timeout as seconds.")) + .arg( + IBC_TRANSFER_MEMO + .def() + .help("Memo field of ICS20 transfer."), + ) } } @@ -3263,10 +3390,14 @@ pub mod args { fn to_sdk(self, ctx: &mut Context) -> TxInitAccount { TxInitAccount:: { tx: self.tx.to_sdk(ctx), - source: ctx.get(&self.source), - vp_code_path: self.vp_code_path.to_path_buf(), - tx_code_path: self.tx_code_path.to_path_buf(), - public_key: ctx.get_cached(&self.public_key), + vp_code_path: self.vp_code_path, + tx_code_path: self.tx_code_path, + public_keys: self + .public_keys + .iter() + .map(|pk| ctx.get_cached(pk)) + .collect(), + threshold: self.threshold, } } } @@ -3274,34 +3405,36 @@ pub mod args { impl Args for TxInitAccount { fn parse(matches: &ArgMatches) -> Self { let tx = Tx::parse(matches); - let source = SOURCE.parse(matches); let vp_code_path = CODE_PATH_OPT .parse(matches) .unwrap_or_else(|| PathBuf::from(VP_USER_WASM)); let tx_code_path = PathBuf::from(TX_INIT_ACCOUNT_WASM); - let public_key = PUBLIC_KEY.parse(matches); + let public_keys = PUBLIC_KEYS.parse(matches); + let threshold = THRESOLD.parse(matches); Self { tx, - source, vp_code_path, - public_key, + public_keys, + threshold, tx_code_path, } } fn def(app: App) -> App { app.add_args::>() - .arg(SOURCE.def().help( - "The source account's address that signs the transaction.", - )) .arg(CODE_PATH_OPT.def().help( "The path to the validity predicate WASM code to be used \ for the new account. Uses the default user VP if none \ specified.", )) - .arg(PUBLIC_KEY.def().help( - "A public key to be used for the new account in \ - hexadecimal encoding.", + .arg(PUBLIC_KEYS.def().help( + "A list public keys to be associated with the new account \ + in hexadecimal encoding.", + )) + .arg(THRESOLD.def().help( + "The minimum number of signature to be provided for \ + authorization. Must be less then the maximum number of \ + public keys provided.", )) } } @@ -3310,9 +3443,13 @@ pub mod args { fn to_sdk(self, ctx: &mut Context) -> TxInitValidator { TxInitValidator:: { tx: self.tx.to_sdk(ctx), - source: ctx.get(&self.source), scheme: self.scheme, - account_key: self.account_key.map(|x| ctx.get_cached(&x)), + account_keys: self + .account_keys + .iter() + .map(|x| ctx.get_cached(x)) + .collect(), + threshold: self.threshold, consensus_key: self.consensus_key.map(|x| ctx.get_cached(&x)), eth_cold_key: self.eth_cold_key.map(|x| ctx.get_cached(&x)), eth_hot_key: self.eth_hot_key.map(|x| ctx.get_cached(&x)), @@ -3331,9 +3468,8 @@ pub mod args { impl Args for TxInitValidator { fn parse(matches: &ArgMatches) -> Self { let tx = Tx::parse(matches); - let source = SOURCE.parse(matches); let scheme = SCHEME.parse(matches); - let account_key = VALIDATOR_ACCOUNT_KEY.parse(matches); + let account_keys = VALIDATOR_ACCOUNT_KEYS.parse(matches); let consensus_key = VALIDATOR_CONSENSUS_KEY.parse(matches); let eth_cold_key = VALIDATOR_ETH_COLD_KEY.parse(matches); let eth_hot_key = VALIDATOR_ETH_HOT_KEY.parse(matches); @@ -3346,11 +3482,12 @@ pub mod args { .unwrap_or_else(|| PathBuf::from(VP_USER_WASM)); let unsafe_dont_encrypt = UNSAFE_DONT_ENCRYPT.parse(matches); let tx_code_path = PathBuf::from(TX_INIT_VALIDATOR_WASM); + let threshold = THRESOLD.parse(matches); Self { tx, - source, scheme, - account_key, + account_keys, + threshold, consensus_key, eth_cold_key, eth_hot_key, @@ -3365,16 +3502,14 @@ pub mod args { fn def(app: App) -> App { app.add_args::>() - .arg(SOURCE.def().help( - "The source account's address that signs the transaction.", - )) .arg(SCHEME.def().help( "The key scheme/type used for the validator keys. \ Currently supports ed25519 and secp256k1.", )) - .arg(VALIDATOR_ACCOUNT_KEY.def().help( - "A public key for the validator account. A new one will \ - be generated if none given.", + .arg(VALIDATOR_ACCOUNT_KEYS.def().help( + "A list public keys to be associated with the new account \ + in hexadecimal encoding. A new one will be generated if \ + none given.", )) .arg(VALIDATOR_CONSENSUS_KEY.def().help( "A consensus key for the validator account. A new one \ @@ -3415,38 +3550,53 @@ pub mod args { "UNSAFE: Do not encrypt the generated keypairs. Do not \ use this for keys used in a live network.", )) + .arg(THRESOLD.def().help( + "The minimum number of signature to be provided for \ + authorization. Must be less then the maximum number of \ + public keys provided.", + )) } } - impl CliToSdk> for TxUpdateVp { - fn to_sdk(self, ctx: &mut Context) -> TxUpdateVp { - TxUpdateVp:: { + impl CliToSdk> for TxUpdateAccount { + fn to_sdk(self, ctx: &mut Context) -> TxUpdateAccount { + TxUpdateAccount:: { tx: self.tx.to_sdk(ctx), vp_code_path: self.vp_code_path, tx_code_path: self.tx_code_path, addr: ctx.get(&self.addr), + public_keys: self + .public_keys + .iter() + .map(|pk| ctx.get_cached(pk)) + .collect(), + threshold: self.threshold, } } } - impl Args for TxUpdateVp { + impl Args for TxUpdateAccount { fn parse(matches: &ArgMatches) -> Self { let tx = Tx::parse(matches); - let vp_code_path = CODE_PATH.parse(matches); + let vp_code_path = CODE_PATH_OPT.parse(matches); let addr = ADDRESS.parse(matches); - let tx_code_path = PathBuf::from(TX_UPDATE_VP_WASM); + let tx_code_path = PathBuf::from(TX_UPDATE_ACCOUNT_WASM); + let public_keys = PUBLIC_KEYS.parse(matches); + let threshold = THRESOLD.parse(matches); Self { tx, vp_code_path, addr, tx_code_path, + public_keys, + threshold, } } fn def(app: App) -> App { app.add_args::>() .arg( - CODE_PATH.def().help( + CODE_PATH_OPT.def().help( "The path to the new validity predicate WASM code.", ), ) @@ -3454,6 +3604,15 @@ pub mod args { "The account's address. It's key is used to produce the \ signature.", )) + .arg(PUBLIC_KEYS.def().help( + "A list public keys to be associated with the new account \ + in hexadecimal encoding.", + )) + .arg(THRESOLD.def().help( + "The minimum number of signature to be provided for \ + authorization. Must be less then the maximum number of \ + public keys provided.", + )) } } @@ -3557,26 +3716,15 @@ pub mod args { )) } } - #[derive(Clone, Debug)] - pub struct InitProposal { - /// Common tx arguments - pub tx: Tx, - /// The proposal file path - pub proposal_data: PathBuf, - /// Flag if proposal should be run offline - pub offline: bool, - /// Native token address - pub native_token: C::NativeAddress, - /// Path to the TX WASM code file - pub tx_code_path: PathBuf, - } impl CliToSdk> for InitProposal { fn to_sdk(self, ctx: &mut Context) -> InitProposal { InitProposal:: { tx: self.tx.to_sdk(ctx), - proposal_data: self.proposal_data, - offline: self.offline, + proposal_data: std::fs::read(self.proposal_data).expect(""), + is_offline: self.is_offline, + is_pgf_stewards: self.is_pgf_stewards, + is_pgf_funding: self.is_pgf_funding, native_token: ctx.native_token.clone(), tx_code_path: self.tx_code_path, } @@ -3587,15 +3735,19 @@ pub mod args { fn parse(matches: &ArgMatches) -> Self { let tx = Tx::parse(matches); let proposal_data = DATA_PATH.parse(matches); - let offline = PROPOSAL_OFFLINE.parse(matches); + let is_offline = PROPOSAL_OFFLINE.parse(matches); + let is_pgf_stewards = PROPOSAL_PGF_STEWARD.parse(matches); + let is_pgf_funding = PROPOSAL_PGF_FUNDING.parse(matches); let tx_code_path = PathBuf::from(TX_INIT_PROPOSAL); Self { tx, proposal_data, - offline, native_token: (), tx_code_path, + is_offline, + is_pgf_stewards, + is_pgf_funding, } } @@ -3607,42 +3759,66 @@ pub mod args { .arg( PROPOSAL_OFFLINE .def() - .help("Flag if the proposal vote should run offline."), + .help( + "Flag if the proposal should be serialized \ + offline (only for default types).", + ) + .conflicts_with_all([ + PROPOSAL_PGF_FUNDING.name, + PROPOSAL_PGF_STEWARD.name, + PROPOSAL_ETH.name, + ]), + ) + .arg( + PROPOSAL_ETH + .def() + .help("Flag if the proposal is of type eth.") + .conflicts_with_all([ + PROPOSAL_PGF_FUNDING.name, + PROPOSAL_PGF_STEWARD.name, + ]), + ) + .arg( + PROPOSAL_PGF_STEWARD + .def() + .help( + "Flag if the proposal is of type pgf-stewards. \ + Used to elect/remove stewards.", + ) + .conflicts_with_all([ + PROPOSAL_ETH.name, + PROPOSAL_PGF_FUNDING.name, + ]), + ) + .arg( + PROPOSAL_PGF_FUNDING + .def() + .help( + "Flag if the proposal is of type pgf-funding. \ + Used to control continous/retro pgf fundings.", + ) + .conflicts_with_all([ + PROPOSAL_ETH.name, + PROPOSAL_PGF_STEWARD.name, + ]), ) } } - #[derive(Clone, Debug)] - pub struct VoteProposal { - /// Common tx arguments - pub tx: Tx, - /// Proposal id - pub proposal_id: Option, - /// The vote - pub vote: String, - /// PGF proposal - pub proposal_pgf: Option, - /// ETH proposal - pub proposal_eth: Option, - /// Flag if proposal vote should be run offline - pub offline: bool, - /// The proposal file path - pub proposal_data: Option, - /// Path to the TX WASM code file - pub tx_code_path: PathBuf, - } - impl CliToSdk> for VoteProposal { fn to_sdk(self, ctx: &mut Context) -> VoteProposal { VoteProposal:: { tx: self.tx.to_sdk(ctx), proposal_id: self.proposal_id, vote: self.vote, - offline: self.offline, - proposal_data: self.proposal_data, + voter: ctx.get(&self.voter), + is_offline: self.is_offline, + proposal_data: self.proposal_data.map(|path| { + println!("Not able to read {}.", path.to_string_lossy()); + std::fs::read(path) + .expect("Should be able to read the file.") + }), tx_code_path: self.tx_code_path.to_path_buf(), - proposal_pgf: self.proposal_pgf, - proposal_eth: self.proposal_eth, } } } @@ -3651,10 +3827,9 @@ pub mod args { fn parse(matches: &ArgMatches) -> Self { let tx = Tx::parse(matches); let proposal_id = PROPOSAL_ID_OPT.parse(matches); - let proposal_pgf = PROPOSAL_VOTE_PGF_OPT.parse(matches); - let proposal_eth = PROPOSAL_VOTE_ETH_OPT.parse(matches); let vote = PROPOSAL_VOTE.parse(matches); - let offline = PROPOSAL_OFFLINE.parse(matches); + let voter = ADDRESS.parse(matches); + let is_offline = PROPOSAL_OFFLINE.parse(matches); let proposal_data = DATA_PATH_OPT.parse(matches); let tx_code_path = PathBuf::from(TX_VOTE_PROPOSAL); @@ -3662,9 +3837,8 @@ pub mod args { tx, proposal_id, vote, - proposal_pgf, - proposal_eth, - offline, + is_offline, + voter, proposal_data, tx_code_path, } @@ -3684,29 +3858,7 @@ pub mod args { .arg( PROPOSAL_VOTE .def() - .help("The vote for the proposal. Either yay or nay"), - ) - .arg( - PROPOSAL_VOTE_PGF_OPT - .def() - .help( - "The list of proposed councils and spending \ - caps:\n$council1 $cap1 $council2 $cap2 ... \ - (council is bech32m encoded address, cap is \ - expressed in microNAM", - ) - .requires(PROPOSAL_ID.name) - .conflicts_with(PROPOSAL_VOTE_ETH_OPT.name), - ) - .arg( - PROPOSAL_VOTE_ETH_OPT - .def() - .help( - "The signing key and message bytes (hex encoded) \ - to be signed: $signing_key $message", - ) - .requires(PROPOSAL_ID.name) - .conflicts_with(PROPOSAL_VOTE_PGF_OPT.name), + .help("The vote for the proposal. Either yay or nay."), ) .arg( PROPOSAL_OFFLINE @@ -3721,8 +3873,10 @@ pub mod args { "The data path file (json) that describes the \ proposal.", ) + .requires(PROPOSAL_OFFLINE.name) .conflicts_with(PROPOSAL_ID.name), ) + .arg(ADDRESS.def().help("The address of the voter.")) } } @@ -3767,7 +3921,7 @@ pub mod args { } fn def(app: App) -> App { - app.add_args::>() + app.add_args::>() .arg(PROPOSAL_ID_OPT.def().help("The proposal identifier.")) } } @@ -3812,7 +3966,15 @@ pub mod args { fn def(app: App) -> App { app.add_args::>() - .arg(PROPOSAL_ID_OPT.def().help("The proposal identifier.")) + .arg( + PROPOSAL_ID_OPT + .def() + .help("The proposal identifier.") + .conflicts_with_all([ + PROPOSAL_OFFLINE.name, + DATA_PATH_OPT.name, + ]), + ) .arg( PROPOSAL_OFFLINE .def() @@ -3820,16 +3982,18 @@ pub mod args { "Flag if the proposal result should run on \ offline data.", ) - .conflicts_with(PROPOSAL_ID.name), + .conflicts_with(PROPOSAL_ID.name) + .requires(DATA_PATH_OPT.name), ) .arg( DATA_PATH_OPT .def() .help( "The path to the folder containing the proposal \ - json and votes", + and votes files in json format.", ) - .conflicts_with(PROPOSAL_ID.name), + .conflicts_with(PROPOSAL_ID.name) + .requires(PROPOSAL_OFFLINE.name), ) } } @@ -3859,6 +4023,26 @@ pub mod args { } } + impl CliToSdk> for QueryPgf { + fn to_sdk(self, ctx: &mut Context) -> QueryPgf { + QueryPgf:: { + query: self.query.to_sdk(ctx), + } + } + } + + impl Args for QueryPgf { + fn parse(matches: &ArgMatches) -> Self { + let query = Query::parse(matches); + + Self { query } + } + + fn def(app: App) -> App { + app.add_args::>() + } + } + impl CliToSdk> for Withdraw { fn to_sdk(self, ctx: &mut Context) -> Withdraw { Withdraw:: { @@ -3932,6 +4116,32 @@ pub mod args { } } + impl CliToSdk> for QueryAccount { + fn to_sdk(self, ctx: &mut Context) -> QueryAccount { + QueryAccount:: { + query: self.query.to_sdk(ctx), + owner: ctx.get(&self.owner), + } + } + } + + impl Args for QueryAccount { + fn parse(matches: &ArgMatches) -> Self { + let query = Query::parse(matches); + let owner = OWNER.parse(matches); + Self { query, owner } + } + + fn def(app: App) -> App { + app.add_args::>().arg( + OWNER + .def() + .help("The substorage space address to query.") + .required(true), + ) + } + } + impl CliToSdk> for QueryBalance { fn to_sdk(self, ctx: &mut Context) -> QueryBalance { QueryBalance:: { @@ -4188,6 +4398,39 @@ pub mod args { } } + impl CliToSdk> for SignTx { + fn to_sdk(self, ctx: &mut Context) -> SignTx { + SignTx:: { + tx: self.tx.to_sdk(ctx), + tx_data: std::fs::read(self.tx_data).expect(""), + owner: ctx.get(&self.owner), + } + } + } + + impl Args for SignTx { + fn parse(matches: &ArgMatches) -> Self { + let tx = Tx::parse(matches); + let tx_path = TX_PATH.parse(matches); + let owner = OWNER.parse(matches); + Self { + tx, + tx_data: tx_path, + owner, + } + } + + fn def(app: App) -> App { + app.add_args::>() + .arg( + TX_PATH.def().help( + "The path to the tx file with the serialized tx.", + ), + ) + .arg(OWNER.def().help("The address of the account owner")) + } + } + impl CliToSdk> for QueryCommissionRate { fn to_sdk(self, ctx: &mut Context) -> QueryCommissionRate { QueryCommissionRate:: { @@ -4342,19 +4585,29 @@ pub mod args { Tx:: { dry_run: self.dry_run, dump_tx: self.dump_tx, + output_folder: self.output_folder, force: self.force, broadcast_only: self.broadcast_only, ledger_address: (), initialized_account_alias: self.initialized_account_alias, wallet_alias_force: self.wallet_alias_force, - fee_amount: self.fee_amount, - fee_token: ctx.get(&self.fee_token), + gas_payer: ctx.get_opt_cached(&self.gas_payer), + gas_amount: self.gas_amount, + gas_token: ctx.get(&self.gas_token), gas_limit: self.gas_limit, - signing_key: self.signing_key.map(|x| ctx.get_cached(&x)), + signing_keys: self + .signing_keys + .iter() + .map(|key| ctx.get_cached(key)) + .collect(), + signatures: self + .signatures + .iter() + .map(|path| std::fs::read(path).unwrap()) + .collect(), verification_key: self .verification_key - .map(|x| ctx.get_cached(&x)), - signer: self.signer.map(|x| ctx.get(&x)), + .map(|public_key| ctx.get_cached(&public_key)), tx_reveal_code_path: self.tx_reveal_code_path, password: self.password, expiration: self.expiration, @@ -4396,6 +4649,10 @@ pub mod args { .arg(WALLET_ALIAS_FORCE.def().help( "Override the alias without confirmation if it already exists.", )) + .arg(GAS_PAYER.def().help( + "The implicit address of the gas payer. It defaults to the \ + address associated to the first key passed to --signing-keys.", + )) .arg(GAS_AMOUNT.def().help( "The amount being paid for the inclusion of this transaction", )) @@ -4412,26 +4669,35 @@ pub mod args { 12:12:12Z\n2012- 12-12T12: 12:12Z", )) .arg( - SIGNING_KEY_OPT + SIGNING_KEYS .def() .help( "Sign the transaction with the key for the given \ public key, public key hash or alias from your \ wallet.", ) - .conflicts_with(SIGNER.name) - .conflicts_with(VERIFICATION_KEY.name), + .conflicts_with_all([ + SIGNATURES.name, + VERIFICATION_KEY.name, + ]), ) .arg( - SIGNER + SIGNATURES .def() .help( - "Sign the transaction with the keypair of the public \ - key of the given address.", + "List of file paths containing a serialized signature \ + to be attached to a transaction. Requires to provide \ + a gas payer.", ) - .conflicts_with(SIGNING_KEY_OPT.name) - .conflicts_with(VERIFICATION_KEY.name), + .conflicts_with_all([ + SIGNING_KEYS.name, + VERIFICATION_KEY.name, + ]) + .requires(GAS_PAYER.name), ) + .arg(OUTPUT_FOLDER_PATH.def().help( + "The output folder path where the artifact will be stored.", + )) .arg( VERIFICATION_KEY .def() @@ -4440,8 +4706,7 @@ pub mod args { public key, public key hash or alias from your \ wallet.", ) - .conflicts_with(SIGNER.name) - .conflicts_with(SIGNING_KEY_OPT.name), + .conflicts_with_all([SIGNING_KEYS.name, SIGNATURES.name]), ) .arg(CHAIN_ID_OPT.def().help("The chain ID.")) } @@ -4454,17 +4719,19 @@ pub mod args { let ledger_address = LEDGER_ADDRESS_DEFAULT.parse(matches); let initialized_account_alias = ALIAS_OPT.parse(matches); let wallet_alias_force = WALLET_ALIAS_FORCE.parse(matches); - let fee_amount = + let gas_payer = GAS_PAYER.parse(matches); + let gas_amount = InputAmount::Unvalidated(GAS_AMOUNT.parse(matches)); - let fee_token = GAS_TOKEN.parse(matches); + let gas_token = GAS_TOKEN.parse(matches); let gas_limit = GAS_LIMIT.parse(matches).amount.into(); let expiration = EXPIRATION_OPT.parse(matches); - let signing_key = SIGNING_KEY_OPT.parse(matches); + let signing_keys = SIGNING_KEYS.parse(matches); + let signatures = SIGNATURES.parse(matches); let verification_key = VERIFICATION_KEY.parse(matches); - let signer = SIGNER.parse(matches); let tx_reveal_code_path = PathBuf::from(TX_REVEAL_PK); let chain_id = CHAIN_ID_OPT.parse(matches); let password = None; + let output_folder = OUTPUT_FOLDER_PATH.parse(matches); Self { dry_run, dump_tx, @@ -4473,16 +4740,18 @@ pub mod args { ledger_address, initialized_account_alias, wallet_alias_force, - fee_amount, - fee_token, + gas_payer, + gas_amount, + gas_token, gas_limit, expiration, - signing_key, + signing_keys, + signatures, verification_key, - signer, tx_reveal_code_path, password, chain_id, + output_folder, } } } diff --git a/apps/src/lib/cli/client.rs b/apps/src/lib/cli/client.rs index 6980874fc6..68ec1728ba 100644 --- a/apps/src/lib/cli/client.rs +++ b/apps/src/lib/cli/client.rs @@ -1,5 +1,6 @@ use color_eyre::eyre::{eyre, Report, Result}; use namada::ledger::eth_bridge::bridge_pool; +use namada::ledger::tx::dump_tx; use namada::ledger::{signing, tx as sdk_tx}; use namada::types::control_flow::ProceedOrElse; use namada::types::io::Io; @@ -80,7 +81,7 @@ impl CliApi { tx::submit_ibc_transfer::<_, IO>(&client, ctx, args) .await?; } - Sub::TxUpdateVp(TxUpdateVp(mut args)) => { + Sub::TxUpdateAccount(TxUpdateAccount(mut args)) => { let client = client.unwrap_or_else(|| { C::from_tendermint_address( &mut args.tx.ledger_address, @@ -91,8 +92,10 @@ impl CliApi { .await .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); - tx::submit_update_vp::<_, IO>(&client, &mut ctx, args) - .await?; + tx::submit_update_account::<_, IO>( + &client, &mut ctx, args, + ) + .await?; } Sub::TxInitAccount(TxInitAccount(mut args)) => { let client = client.unwrap_or_else(|| { @@ -250,37 +253,59 @@ impl CliApi { .proceed_or_else(error)?; let args = args.to_sdk(&mut ctx); let tx_args = args.tx.clone(); - let (mut tx, addr, pk) = - bridge_pool::build_bridge_pool_tx::<_, _, IO>( + + let default_signer = Some(args.sender.clone()); + let signing_data = + signing::aux_signing_data::<_, _, IO>( &client, &mut ctx.wallet, - args, + &args.tx, + &Some(args.sender.clone()), + default_signer, ) - .await - .unwrap(); - tx::submit_reveal_aux::<_, IO>( - &client, - &mut ctx, - &tx_args, - addr, - pk.clone(), - &mut tx, - ) - .await?; - signing::sign_tx( - &mut ctx.wallet, - &mut tx, - &tx_args, - &pk, - ) - .await?; - sdk_tx::process_tx::<_, _, IO>( + .await?; + + let mut tx = + bridge_pool::build_bridge_pool_tx::<_, IO>( + &client, + args.clone(), + signing_data.gas_payer.clone(), + ) + .await?; + + signing::generate_test_vector::<_, _, IO>( &client, &mut ctx.wallet, - &tx_args, - tx, + &tx, ) - .await?; + .await; + + if args.tx.dump_tx { + dump_tx::(&args.tx, tx); + } else { + tx::submit_reveal_aux::<_, IO>( + &client, + &mut ctx, + tx_args.clone(), + &args.sender, + ) + .await?; + + signing::sign_tx( + &mut ctx.wallet, + &tx_args, + &mut tx, + signing_data, + ); + + sdk_tx::process_tx::<_, _, IO>( + &client, + &mut ctx.wallet, + &tx_args, + tx, + ) + .await?; + } } Sub::TxUnjailValidator(TxUnjailValidator(mut args)) => { let client = client.unwrap_or_else(|| { @@ -562,6 +587,45 @@ impl CliApi { rpc::query_protocol_parameters::<_, IO>(&client, args) .await; } + Sub::QueryPgf(QueryPgf(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced::() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + rpc::query_pgf::<_, IO>(&client, args).await; + } + Sub::QueryAccount(QueryAccount(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced::() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + rpc::query_account::<_, IO>(&client, args).await; + } + Sub::SignTx(SignTx(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.tx.ledger_address, + ) + }); + client + .wait_until_node_is_synced::() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + tx::sign_tx::<_, IO>(&client, &mut ctx, args).await?; + } } } cli::NamadaClient::WithoutContext(cmd, global_args) => match cmd { diff --git a/apps/src/lib/cli/utils.rs b/apps/src/lib/cli/utils.rs index c35298976c..4ae8e4adbc 100644 --- a/apps/src/lib/cli/utils.rs +++ b/apps/src/lib/cli/utils.rs @@ -225,6 +225,27 @@ where } } +impl ArgMulti> +where + T: FromStr, + ::Err: Debug, +{ + pub fn def(&self) -> ClapArg { + ClapArg::new(self.name) + .long(self.name) + .num_args(1..) + .value_delimiter(',') + } + + pub fn parse(&self, matches: &ArgMatches) -> Vec> { + matches + .get_many(self.name) + .unwrap_or_default() + .map(|raw: &String| FromContext::new(raw.to_string())) + .collect() + } +} + impl ArgDefaultFromCtx> where T: FromStr, diff --git a/apps/src/lib/client/mod.rs b/apps/src/lib/client/mod.rs index 57f3c5a043..8862c5a564 100644 --- a/apps/src/lib/client/mod.rs +++ b/apps/src/lib/client/mod.rs @@ -1,4 +1,3 @@ pub mod rpc; -pub mod signing; pub mod tx; pub mod utils; diff --git a/apps/src/lib/client/rpc.rs b/apps/src/lib/client/rpc.rs index efdc8ee8c3..a49be3f89e 100644 --- a/apps/src/lib/client/rpc.rs +++ b/apps/src/lib/client/rpc.rs @@ -2,10 +2,9 @@ use std::cmp::Ordering; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; -use std::fs::File; +use std::fs::{self, read_dir}; use std::io; use std::iter::Iterator; -use std::path::PathBuf; use std::str::FromStr; use borsh::{BorshDeserialize, BorshSerialize}; @@ -15,22 +14,28 @@ use masp_primitives::asset_type::AssetType; use masp_primitives::merkle_tree::MerklePath; use masp_primitives::sapling::{Node, ViewingKey}; use masp_primitives::zip32::ExtendedFullViewingKey; -use namada::core::types::transaction::governance::ProposalType; +use namada::core::ledger::governance::cli::offline::{ + find_offline_proposal, find_offline_votes, read_offline_files, + OfflineSignedProposal, OfflineVote, +}; +use namada::core::ledger::governance::parameters::GovernanceParameters; +use namada::core::ledger::governance::storage::keys as governance_storage; +use namada::core::ledger::governance::storage::proposal::{ + PGFTarget, StorageProposal, +}; +use namada::core::ledger::governance::utils::{ + compute_proposal_result, ProposalVotes, TallyType, TallyVote, VotePower, +}; use namada::ledger::events::Event; -use namada::ledger::governance::parameters::GovParams; -use namada::ledger::governance::storage as gov_storage; use namada::ledger::masp::{ Conversions, MaspAmount, MaspChange, PinnedBalanceError, ShieldedContext, ShieldedUtils, }; -use namada::ledger::native_vp::governance::utils::{self, Votes}; use namada::ledger::parameters::{storage as param_storage, EpochDuration}; -use namada::ledger::pos::{ - self, BondId, BondsAndUnbondsDetail, CommissionPair, PosParams, Slash, -}; +use namada::ledger::pos::{CommissionPair, PosParams, Slash}; use namada::ledger::queries::RPC; use namada::ledger::rpc::{ - enriched_bonds_and_unbonds, format_denominated_amount, query_epoch, + self, enriched_bonds_and_unbonds, format_denominated_amount, query_epoch, TxResponse, }; use namada::ledger::storage::ConversionState; @@ -38,9 +43,6 @@ use namada::ledger::wallet::{AddressVpType, Wallet}; use namada::proof_of_stake::types::{ValidatorState, WeightedValidator}; use namada::types::address::{masp, Address}; use namada::types::control_flow::ProceedOrElse; -use namada::types::governance::{ - OfflineProposal, OfflineVote, ProposalVote, VotePower, VoteType, -}; use namada::types::hash::Hash; use namada::types::io::Io; use namada::types::key::*; @@ -377,7 +379,7 @@ pub async fn query_transparent_balance< client, &token, balance, ) .await; - println!("{}: {}", token_alias, balance); + display_line!(IO, "{}: {}", token_alias, balance); } } } @@ -650,162 +652,51 @@ pub async fn query_proposal< client: &C, args: args::QueryProposal, ) { - async fn print_proposal< - C: namada::ledger::queries::Client + Sync, - IO: Io, - >( - client: &C, - id: u64, - current_epoch: Epoch, - details: bool, - ) -> Option<()> { - let author_key = gov_storage::get_author_key(id); - let start_epoch_key = gov_storage::get_voting_start_epoch_key(id); - let end_epoch_key = gov_storage::get_voting_end_epoch_key(id); - let proposal_type_key = gov_storage::get_proposal_type_key(id); - - let author = - query_storage_value::(client, &author_key).await?; - let start_epoch = - query_storage_value::(client, &start_epoch_key).await?; - let end_epoch = - query_storage_value::(client, &end_epoch_key).await?; - let proposal_type = - query_storage_value::(client, &proposal_type_key) - .await?; - - if details { - let content_key = gov_storage::get_content_key(id); - let grace_epoch_key = gov_storage::get_grace_epoch_key(id); - let content = query_storage_value::>( - client, - &content_key, - ) - .await?; - let grace_epoch = - query_storage_value::(client, &grace_epoch_key) - .await?; - - display_line!(IO, "Proposal: {}", id); - display_line!(IO, "{:4}Type: {}", "", proposal_type); - display_line!(IO, "{:4}Author: {}", "", author); - display_line!(IO, "{:4}Content:", ""); - for (key, value) in &content { - display_line!(IO, "{:8}{}: {}", "", key, value); - } - display_line!(IO, "{:4}Start Epoch: {}", "", start_epoch); - display_line!(IO, "{:4}End Epoch: {}", "", end_epoch); - display_line!(IO, "{:4}Grace Epoch: {}", "", grace_epoch); - let votes = - get_proposal_votes::<_, IO>(client, start_epoch, id).await; - let total_stake = get_total_staked_tokens(client, start_epoch) + let current_epoch = query_and_print_epoch::<_, IO>(client).await; + + if let Some(id) = args.proposal_id { + let proposal = query_proposal_by_id(client, id).await; + if let Some(proposal) = proposal { + display_line!( + IO, + "{}", + proposal.to_string_with_status(current_epoch) + ); + } else { + edisplay_line!(IO, "No proposal found with id: {}", id); + } + } else { + let last_proposal_id_key = governance_storage::get_counter_key(); + let last_proposal_id = + query_storage_value::(client, &last_proposal_id_key) .await - .try_into() .unwrap(); - if start_epoch > current_epoch { - display_line!(IO, "{:4}Status: pending", ""); - } else if start_epoch <= current_epoch && current_epoch <= end_epoch - { - match utils::compute_tally(votes, total_stake, &proposal_type) { - Ok(partial_proposal_result) => { - display_line!( - IO, - "{:4}Yay votes: {}", - "", - partial_proposal_result.total_yay_power - ); - display_line!( - IO, - "{:4}Nay votes: {}", - "", - partial_proposal_result.total_nay_power - ); - display_line!(IO, "{:4}Status: on-going", ""); - } - Err(msg) => { - edisplay_line!( - IO, - "Error in tally computation: {}", - msg - ); - } - } - } else { - match utils::compute_tally(votes, total_stake, &proposal_type) { - Ok(proposal_result) => { - display_line!(IO, "{:4}Status: done", ""); - display_line!( - IO, - "{:4}Result: {}", - "", - proposal_result - ); - } - Err(msg) => { - edisplay_line!( - IO, - "Error in tally computation: {}", - msg - ); - } - } - } + + let from_id = if last_proposal_id > 10 { + last_proposal_id - 10 } else { - display_line!(IO, "Proposal: {}", id); - display_line!(IO, "{:4}Type: {}", "", proposal_type); - display_line!(IO, "{:4}Author: {}", "", author); - display_line!(IO, "{:4}Start Epoch: {}", "", start_epoch); - display_line!(IO, "{:4}End Epoch: {}", "", end_epoch); - if start_epoch > current_epoch { - display_line!(IO, "{:4}Status: pending", ""); - } else if start_epoch <= current_epoch && current_epoch <= end_epoch - { - display_line!(IO, "{:4}Status: on-going", ""); - } else { - display_line!(IO, "{:4}Status: done", ""); - } - } + 0 + }; - Some(()) - } + display_line!(IO, "id: {}", last_proposal_id); - let current_epoch = query_and_print_epoch::<_, IO>(client).await; - match args.proposal_id { - Some(id) => { - if print_proposal::(client, id, current_epoch, true) + for id in from_id..last_proposal_id { + let proposal = query_proposal_by_id(client, id) .await - .is_none() - { - edisplay_line!( - IO, - "No valid proposal was found with id {}", - id - ); - } - } - None => { - let last_proposal_id_key = gov_storage::get_counter_key(); - let last_proposal_id = - query_storage_value::(client, &last_proposal_id_key) - .await - .unwrap(); - - for id in 0..last_proposal_id { - if print_proposal::(client, id, current_epoch, false) - .await - .is_none() - { - edisplay_line!( - IO, - "No valid proposal was found with id {}", - id - ); - }; - } + .expect("Proposal should be written to storage."); + display_line!(IO, "{}", proposal); } } } +/// Query proposal by Id +pub async fn query_proposal_by_id( + client: &C, + proposal_id: u64, +) -> Option { + namada::ledger::rpc::query_proposal_by_id(client, proposal_id).await +} + /// Query token shielded balance(s) pub async fn query_shielded_balance< C: namada::ledger::queries::Client + Sync, @@ -1119,196 +1010,159 @@ pub async fn query_proposal_result< client: &C, args: args::QueryProposalResult, ) { - let current_epoch = query_epoch(client).await; + if args.proposal_id.is_some() { + let proposal_id = + args.proposal_id.expect("Proposal id should be defined."); + let proposal = if let Some(proposal) = + query_proposal_by_id(client, proposal_id).await + { + proposal + } else { + edisplay_line!(IO, "Proposal {} not found.", proposal_id); + return; + }; - match args.proposal_id { - Some(id) => { - let end_epoch_key = gov_storage::get_voting_end_epoch_key(id); - let end_epoch = - query_storage_value::(client, &end_epoch_key).await; - - match end_epoch { - Some(end_epoch) => { - if current_epoch > end_epoch { - let votes = - get_proposal_votes::<_, IO>(client, end_epoch, id) - .await; - let proposal_type_key = - gov_storage::get_proposal_type_key(id); - let proposal_type = query_storage_value::< - C, - ProposalType, - >( - client, &proposal_type_key - ) - .await - .expect("Could not read proposal type from storage"); - let total_stake = - get_total_staked_tokens(client, end_epoch) - .await - .try_into() - .unwrap(); - display_line!(IO, "Proposal: {}", id); - match utils::compute_tally( - votes, - total_stake, - &proposal_type, - ) { - Ok(proposal_result) => { - display_line!( - IO, - "{:4}Result: {}", - "", - proposal_result - ); - } - Err(msg) => { - edisplay_line!( - IO, - "Error in tally computation: {}", - msg - ); - } - } - } else { - edisplay_line!(IO, "Proposal is still in progress."); - cli::safe_exit(1) - } - } - None => { - edisplay_line!(IO, "Error while retriving proposal."); - cli::safe_exit(1) - } - } - } - None => { - if args.offline { - match args.proposal_folder { - Some(path) => { - let mut dir = tokio::fs::read_dir(&path) - .await - .expect("Should be able to read the directory."); - let mut files = HashSet::new(); - let mut is_proposal_present = false; - - while let Some(entry) = - dir.next_entry().await.transpose() - { - match entry { - Ok(entry) => match entry.file_type().await { - Ok(entry_stat) => { - if entry_stat.is_file() { - if entry.file_name().eq(&"proposal") - { - is_proposal_present = true - } else if entry - .file_name() - .to_string_lossy() - .starts_with("proposal-vote-") - { - // Folder may contain other - // files than just the proposal - // and the votes - files.insert(entry.path()); - } - } - } - Err(e) => { - edisplay_line!( - IO, - "Can't read entry type: {}.", - e - ); - cli::safe_exit(1) - } - }, - Err(e) => { - edisplay_line!( - IO, - "Can't read entry: {}.", - e - ); - cli::safe_exit(1) - } - } - } + let tally_type = proposal.get_tally_type(); + let total_voting_power = + get_total_staked_tokens(client, proposal.voting_end_epoch).await; - if !is_proposal_present { - edisplay_line!( - IO, - "The folder must contain the offline proposal \ - in a file named \"proposal\"" - ); - cli::safe_exit(1) - } + let votes = compute_proposal_votes( + client, + proposal_id, + proposal.voting_end_epoch, + ) + .await; - let file = File::open(path.join("proposal")) - .expect("Proposal file must exist."); - let proposal: OfflineProposal = - serde_json::from_reader(file).expect( - "JSON was not well-formatted for proposal.", - ); - - let public_key = - get_public_key(client, &proposal.address) - .await - .expect("Public key should exist."); - - if !proposal.check_signature(&public_key) { - edisplay_line!(IO, "Bad proposal signature."); - cli::safe_exit(1) - } + let proposal_result = + compute_proposal_result(votes, total_voting_power, tally_type); - let votes = get_proposal_offline_votes( - client, - proposal.clone(), - files, - ) - .await; - let total_stake = get_total_staked_tokens( - client, - proposal.tally_epoch, - ) - .await - .try_into() - .unwrap(); - match utils::compute_tally( - votes, - total_stake, - &ProposalType::Default(None), - ) { - Ok(proposal_result) => { - display_line!( - IO, - "{:4}Result: {}", - "", - proposal_result - ); - } - Err(msg) => { - edisplay_line!( - IO, - "Error in tally computation: {}", - msg - ); - } - } - } - None => { - edisplay_line!( - IO, - "Offline flag must be followed by data-path." - ); - cli::safe_exit(1) - } - }; + display_line!(IO, "Proposal Id: {} ", proposal_id); + display_line!(IO, "{:4}{}", "", proposal_result); + } else { + let proposal_folder = args.proposal_folder.expect( + "The argument --proposal-folder is required with --offline.", + ); + let data_directory = read_dir(&proposal_folder).unwrap_or_else(|_| { + panic!( + "Should be able to read {} directory.", + proposal_folder.to_string_lossy() + ) + }); + let files = read_offline_files(data_directory); + let proposal_path = find_offline_proposal(&files); + + let proposal = if let Some(path) = proposal_path { + let proposal_file = + fs::File::open(path).expect("file should open read only"); + let proposal: OfflineSignedProposal = + serde_json::from_reader(proposal_file) + .expect("file should be proper JSON"); + + let author_account = + rpc::get_account_info(client, &proposal.proposal.author) + .await + .expect("Account should exist."); + + let proposal = proposal.validate( + &author_account.public_keys_map, + author_account.threshold, + ); + + if proposal.is_ok() { + proposal.unwrap() } else { - edisplay_line!( + edisplay_line!(IO, "The offline proposal is not valid."); + return; + } + } else { + edisplay_line!( + IO, + "Couldn't find a file name offline_proposal_*.json." + ); + return; + }; + + let votes = find_offline_votes(&files) + .iter() + .map(|path| { + let vote_file = fs::File::open(path).expect(""); + let vote: OfflineVote = + serde_json::from_reader(vote_file).expect(""); + vote + }) + .collect::>(); + + let proposal_votes = compute_offline_proposal_votes::<_, IO>( + client, + &proposal, + votes.clone(), + ) + .await; + let total_voting_power = + get_total_staked_tokens(client, proposal.proposal.tally_epoch) + .await; + + let proposal_result = compute_proposal_result( + proposal_votes, + total_voting_power, + TallyType::TwoThird, + ); + + display_line!(IO, "Proposal offline: {}", proposal.proposal.hash()); + display_line!(IO, "Parsed {} votes.", votes.len()); + display_line!(IO, "{:4}{}", "", proposal_result); + } +} + +pub async fn query_account< + C: namada::ledger::queries::Client + Sync, + IO: Io, +>( + client: &C, + args: args::QueryAccount, +) { + let account = rpc::get_account_info(client, &args.owner).await; + if let Some(account) = account { + display_line!(IO, "Address: {}", account.address); + display_line!(IO, "Threshold: {}", account.threshold); + display_line!(IO, "Public keys:"); + for (public_key, _) in account.public_keys_map.pk_to_idx { + display_line!(IO, "- {}", public_key); + } + } else { + display_line!(IO, "No account exists for {}", args.owner); + } +} + +pub async fn query_pgf( + client: &C, + _args: args::QueryPgf, +) { + let stewards = query_pgf_stewards(client).await; + let fundings = query_pgf_fundings(client).await; + + match stewards.len() { + 0 => display_line!(IO, "Pgf stewards: no stewards are currectly set."), + _ => { + display_line!(IO, "Pgf stewards:"); + for steward in stewards { + display_line!(IO, "{:4}- {}", "", steward); + } + } + } + + match fundings.len() { + 0 => display_line!(IO, "Pgf fundings: no fundings are currently set."), + _ => { + display_line!(IO, "Pgf fundings:"); + for payment in fundings { + display_line!(IO, "{:4}- {}", "", payment.target); + display_line!( IO, - "Either --proposal-id or --data-path should be provided \ - as arguments." + "{:6}{}", + "", + payment.amount.to_string_native() ); - cli::safe_exit(1) } } } @@ -1321,7 +1175,7 @@ pub async fn query_protocol_parameters< client: &C, _args: args::QueryProtocolParameters, ) { - let gov_parameters = get_governance_parameters(client).await; + let gov_parameters = query_governance_parameters(client).await; display_line!(IO, "Governance Parameters\n {:4}", gov_parameters); display_line!(IO, "Protocol parameters"); @@ -1361,10 +1215,7 @@ pub async fn query_protocol_parameters< display_line!(IO, "{:4}Transactions whitelist: {:?}", "", tx_whitelist); display_line!(IO, "PoS parameters"); - let key = pos::params_key(); - let pos_params = query_storage_value::(client, &key) - .await - .expect("Parameter should be defined."); + let pos_params = query_pos_parameters(client).await; display_line!( IO, "{:4}Block proposer reward: {}", @@ -1431,6 +1282,30 @@ pub async fn query_unbond_with_slashing< ) } +pub async fn query_pos_parameters( + client: &C, +) -> PosParams { + unwrap_client_response::( + RPC.vp().pos().pos_params(client).await, + ) +} + +pub async fn query_pgf_stewards( + client: &C, +) -> BTreeSet
{ + unwrap_client_response::>( + RPC.vp().pgf().stewards(client).await, + ) +} + +pub async fn query_pgf_fundings( + client: &C, +) -> BTreeSet { + unwrap_client_response::>( + RPC.vp().pgf().funding(client).await, + ) +} + pub async fn query_and_print_unbonds< C: namada::ledger::queries::Client + Sync, IO: Io, @@ -2036,8 +1911,9 @@ where pub async fn get_public_key( client: &C, address: &Address, + index: u8, ) -> Option { - namada::ledger::rpc::get_public_key(client, address).await + namada::ledger::rpc::get_public_key_at(client, address, index).await } /// Check if the given address is a known validator. @@ -2301,203 +2177,6 @@ pub async fn epoch_sleep( } } -pub async fn get_proposal_votes< - C: namada::ledger::queries::Client + Sync, - IO: Io, ->( - client: &C, - epoch: Epoch, - proposal_id: u64, -) -> Votes { - namada::ledger::rpc::get_proposal_votes::<_, IO>(client, epoch, proposal_id) - .await -} - -pub async fn get_proposal_offline_votes< - C: namada::ledger::queries::Client + Sync, ->( - client: &C, - proposal: OfflineProposal, - files: HashSet, -) -> Votes { - // let validators = get_all_validators(client, proposal.tally_epoch).await; - - let proposal_hash = proposal.compute_hash(); - - let mut yay_validators: HashMap = - HashMap::new(); - let mut delegators: HashMap< - Address, - HashMap, - > = HashMap::new(); - - for path in files { - let file = File::open(&path).expect("Proposal file must exist."); - let proposal_vote: OfflineVote = serde_json::from_reader(file) - .expect("JSON was not well-formatted for offline vote."); - - let key = pk_key(&proposal_vote.address); - let public_key = query_storage_value(client, &key) - .await - .expect("Public key should exist."); - - if !proposal_vote.proposal_hash.eq(&proposal_hash) - || !proposal_vote.check_signature(&public_key) - { - continue; - } - - if proposal_vote.vote.is_yay() - // && validators.contains(&proposal_vote.address) - && unwrap_client_response::( - RPC.vp().pos().is_validator(client, &proposal_vote.address).await, - ) - { - let amount: VotePower = get_validator_stake( - client, - proposal.tally_epoch, - &proposal_vote.address, - ) - .await - .unwrap_or_default() - .try_into() - .expect("Amount out of bounds"); - yay_validators.insert( - proposal_vote.address, - (amount, ProposalVote::Yay(VoteType::Default)), - ); - } else if is_delegator_at( - client, - &proposal_vote.address, - proposal.tally_epoch, - ) - .await - { - // TODO: decide whether to do this with `bond_with_slashing` RPC - // endpoint or with `bonds_and_unbonds` - let bonds_and_unbonds: pos::types::BondsAndUnbondsDetails = - unwrap_client_response::( - RPC.vp() - .pos() - .bonds_and_unbonds( - client, - &Some(proposal_vote.address.clone()), - &None, - ) - .await, - ); - for ( - BondId { - source: _, - validator, - }, - BondsAndUnbondsDetail { - bonds, - unbonds: _, - slashes: _, - }, - ) in bonds_and_unbonds - { - let mut delegated_amount = token::Amount::zero(); - for delta in bonds { - if delta.start <= proposal.tally_epoch { - delegated_amount += delta.amount - - delta.slashed_amount.unwrap_or_default(); - } - } - - let entry = delegators - .entry(proposal_vote.address.clone()) - .or_default(); - entry.insert( - validator, - ( - VotePower::try_from(delegated_amount).unwrap(), - proposal_vote.vote.clone(), - ), - ); - } - - // let key = pos::bonds_for_source_prefix(&proposal_vote.address); - // let bonds_iter = - // query_storage_prefix::(client, &key).await; - // if let Some(bonds) = bonds_iter { - // for (key, epoched_bonds) in bonds { - // // Look-up slashes for the validator in this key and - // // apply them if any - // let validator = - // pos::get_validator_address_from_bond(&key) - // .expect( - // "Delegation key should contain validator - // address.", ); - // let slashes_key = pos::validator_slashes_key(&validator); - // let slashes = query_storage_value::( - // client, - // &slashes_key, - // ) - // .await - // .unwrap_or_default(); - // let mut delegated_amount: token::Amount = 0.into(); - // let bond = epoched_bonds - // .get(proposal.tally_epoch) - // .expect("Delegation bond should be defined."); - // let mut to_deduct = bond.neg_deltas; - // for (start_epoch, &(mut delta)) in - // bond.pos_deltas.iter().sorted() - // { - // // deduct bond's neg_deltas - // if to_deduct > delta { - // to_deduct -= delta; - // // If the whole bond was deducted, continue to - // // the next one - // continue; - // } else { - // delta -= to_deduct; - // to_deduct = token::Amount::zero(); - // } - - // delta = apply_slashes( - // &slashes, - // delta, - // *start_epoch, - // None, - // None, - // ); - // delegated_amount += delta; - // } - - // let validator_address = - // pos::get_validator_address_from_bond(&key).expect( - // "Delegation key should contain validator - // address.", ); - // if proposal_vote.vote.is_yay() { - // let entry = yay_delegators - // .entry(proposal_vote.address.clone()) - // .or_default(); - // entry.insert( - // validator_address, - // VotePower::from(delegated_amount), - // ); - // } else { - // let entry = nay_delegators - // .entry(proposal_vote.address.clone()) - // .or_default(); - // entry.insert( - // validator_address, - // VotePower::from(delegated_amount), - // ); - // } - // } - // } - } - } - - Votes { - yay_validators, - delegators, - } -} - pub async fn get_bond_amount_at( client: &C, delegator: &Address, @@ -2556,12 +2235,23 @@ pub async fn get_delegators_delegation< namada::ledger::rpc::get_delegators_delegation(client, address).await } -pub async fn get_governance_parameters< +pub async fn get_delegators_delegation_at< C: namada::ledger::queries::Client + Sync, >( client: &C, -) -> GovParams { - namada::ledger::rpc::get_governance_parameters(client).await + address: &Address, + epoch: Epoch, +) -> HashMap { + namada::ledger::rpc::get_delegators_delegation_at(client, address, epoch) + .await +} + +pub async fn query_governance_parameters< + C: namada::ledger::queries::Client + Sync, +>( + client: &C, +) -> GovernanceParameters { + namada::ledger::rpc::query_governance_parameters(client).await } /// A helper to unwrap client's response. Will shut down process on error. @@ -2573,3 +2263,123 @@ fn unwrap_client_response( cli::safe_exit(1) }) } + +pub async fn compute_offline_proposal_votes< + C: namada::ledger::queries::Client + Sync, + IO: Io, +>( + client: &C, + proposal: &OfflineSignedProposal, + votes: Vec, +) -> ProposalVotes { + let mut validators_vote: HashMap = HashMap::default(); + let mut validator_voting_power: HashMap = + HashMap::default(); + let mut delegators_vote: HashMap = HashMap::default(); + let mut delegator_voting_power: HashMap< + Address, + HashMap, + > = HashMap::default(); + for vote in votes { + let is_validator = is_validator(client, &vote.address).await; + let is_delegator = is_delegator(client, &vote.address).await; + if is_validator { + let validator_stake = get_validator_stake( + client, + proposal.proposal.tally_epoch, + &vote.address, + ) + .await + .unwrap_or_default(); + validators_vote.insert(vote.address.clone(), vote.clone().into()); + validator_voting_power + .insert(vote.address.clone(), validator_stake); + } else if is_delegator { + let validators = get_delegators_delegation_at( + client, + &vote.address.clone(), + proposal.proposal.tally_epoch, + ) + .await; + + for validator in vote.delegations.clone() { + let delegator_stake = + validators.get(&validator).cloned().unwrap_or_default(); + + delegators_vote + .insert(vote.address.clone(), vote.clone().into()); + delegator_voting_power + .entry(vote.address.clone()) + .or_default() + .insert(validator, delegator_stake); + } + } else { + display_line!( + IO, + "Skipping vote, not a validator/delegator at epoch {}.", + proposal.proposal.tally_epoch + ); + } + } + + ProposalVotes { + validators_vote, + validator_voting_power, + delegators_vote, + delegator_voting_power, + } +} + +pub async fn compute_proposal_votes< + C: namada::ledger::queries::Client + Sync, +>( + client: &C, + proposal_id: u64, + epoch: Epoch, +) -> ProposalVotes { + let votes = + namada::ledger::rpc::query_proposal_votes(client, proposal_id).await; + + let mut validators_vote: HashMap = HashMap::default(); + let mut validator_voting_power: HashMap = + HashMap::default(); + let mut delegators_vote: HashMap = HashMap::default(); + let mut delegator_voting_power: HashMap< + Address, + HashMap, + > = HashMap::default(); + + for vote in votes { + if vote.is_validator() { + let validator_stake = + get_validator_stake(client, epoch, &vote.validator.clone()) + .await + .unwrap_or_default(); + + validators_vote.insert(vote.validator.clone(), vote.data.into()); + validator_voting_power.insert(vote.validator, validator_stake); + } else { + let delegator_stake = get_bond_amount_at( + client, + &vote.delegator, + &vote.validator, + epoch, + ) + .await + .unwrap_or_default(); + + delegators_vote.insert(vote.delegator.clone(), vote.data.into()); + delegator_voting_power + .entry(vote.delegator.clone()) + .or_default() + .insert(vote.validator, delegator_stake); + } + } + + ProposalVotes { + validators_vote, + validator_voting_power, + delegators_vote, + delegator_voting_power, + } +} diff --git a/apps/src/lib/client/signing.rs b/apps/src/lib/client/signing.rs index 34ee2bcc29..dd855b0d5e 100644 --- a/apps/src/lib/client/signing.rs +++ b/apps/src/lib/client/signing.rs @@ -33,7 +33,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, @@ -44,7 +44,7 @@ where C::Error: std::fmt::Display, U: WalletUtils, { - namada::ledger::signing::tx_signer::( + 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 1d6144454c..3398c1686f 100644 --- a/apps/src/lib/client/tx.rs +++ b/apps/src/lib/client/tx.rs @@ -1,4 +1,3 @@ -use std::collections::HashSet; use std::env; use std::fmt::Debug; use std::fs::{File, OpenOptions}; @@ -7,34 +6,29 @@ use std::path::PathBuf; use async_trait::async_trait; use borsh::{BorshDeserialize, BorshSerialize}; -use data_encoding::HEXLOWER_PERMISSIVE; use masp_proofs::prover::LocalTxProver; -use namada::ledger::governance::storage as gov_storage; +use namada::core::ledger::governance::cli::offline::{ + OfflineSignedProposal, OfflineVote, +}; +use namada::core::ledger::governance::cli::onchain::{ + DefaultProposal, PgfFundingProposal, PgfStewardProposal, ProposalVote, +}; use namada::ledger::queries::Client; use namada::ledger::rpc::{TxBroadcastData, TxResponse}; -use namada::ledger::signing::TxSigningKey; 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::proto::Tx; +use namada::types::address::{Address, ImplicitAddress}; use namada::types::dec::Dec; -use namada::types::governance::{ - OfflineProposal, OfflineVote, Proposal, ProposalVote, VoteType, -}; use namada::types::io::Io; use namada::types::key::{self, *}; -use namada::types::storage::{Epoch, Key}; -use namada::types::token; -use namada::types::transaction::governance::{ProposalType, VoteProposalData}; -use namada::types::transaction::{InitValidator, TxType}; +use namada::types::transaction::pos::InitValidator; use namada::{display_line, edisplay_line}; use super::rpc; -use crate::cli::context::WalletAddress; use crate::cli::{args, safe_exit, Context}; use crate::client::rpc::query_wasm_code_hash; -use crate::client::signing::find_pk; use crate::client::tx::tx::ProcessTxResponse; use crate::config::TendermintMode; use crate::facade::tendermint_rpc::endpoint::broadcast::tx_sync::Response; @@ -48,35 +42,53 @@ pub async fn submit_reveal_aux< >( client: &C, ctx: &mut Context, - args: &args::Tx, - addr: Option
, - pk: common::PublicKey, - tx: &mut Tx, + args: args::Tx, + address: &Address, ) -> Result<(), tx::Error> { - if let Some(Address::Implicit(_)) = addr { - let reveal_pk = tx::build_reveal_pk::<_, _, IO>( - client, - &mut ctx.wallet, - args::RevealPk { - tx: args.clone(), - public_key: pk.clone(), - }, - ) - .await?; - if let Some((mut rtx, _, pk)) = reveal_pk { - // Sign the reveal public key transaction with the fee payer - signing::sign_tx(&mut ctx.wallet, &mut rtx, args, &pk).await?; - // Submit the reveal public key transaction first - tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, args, rtx) - .await?; - // Update the stateful PoW challenge of the outer transaction - #[cfg(not(feature = "mainnet"))] - signing::update_pow_challenge::<_, IO>( - client, args, tx, &pk, false, + if args.dump_tx { + return Ok(()); + } + + 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 signing_data = signing::aux_signing_data::<_, _, IO>( + client, + &mut ctx.wallet, + &args, + &None, + None, + ) + .await?; + + let mut tx = tx::build_reveal_pk_aux::( + client, + &args, + address, + &public_key, + &signing_data.gas_payer, + ) + .await?; + + signing::generate_test_vector::<_, _, IO>( + client, + &mut ctx.wallet, + &tx, ) .await; + + signing::sign_tx(&mut ctx.wallet, &args, &mut tx, signing_data); + + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args, tx) + .await?; } } + Ok(()) } @@ -89,46 +101,77 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, pk) = - tx::build_custom::<_, _, IO>(client, &mut ctx.wallet, args.clone()) - .await?; - submit_reveal_aux::<_, IO>( + let default_signer = Some(args.owner.clone()); + let signing_data = signing::aux_signing_data::<_, _, IO>( client, - ctx, + &mut ctx.wallet, &args.tx, - addr, - pk.clone(), - &mut tx, + &Some(args.owner.clone()), + default_signer, + ) + .await?; + + submit_reveal_aux::<_, IO>(client, ctx, args.tx.clone(), &args.owner) + .await?; + + let mut tx = tx::build_custom::<_, IO>( + client, + args.clone(), + &signing_data.gas_payer, ) .await?; - signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx).await?; + + signing::generate_test_vector::<_, _, IO>(client, &mut ctx.wallet, &tx) + .await; + + if args.tx.dump_tx { + tx::dump_tx::(&args.tx, tx); + } else { + signing::sign_tx(&mut ctx.wallet, &args.tx, &mut tx, signing_data); + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx) + .await?; + } + Ok(()) } -pub async fn submit_update_vp( +pub async fn submit_update_account( client: &C, ctx: &mut Context, - args: args::TxUpdateVp, + args: args::TxUpdateAccount, ) -> Result<(), tx::Error> where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, pk) = - tx::build_update_vp::<_, _, IO>(client, &mut ctx.wallet, args.clone()) - .await?; - submit_reveal_aux::<_, IO>( + let default_signer = Some(args.addr.clone()); + let signing_data = signing::aux_signing_data::<_, _, IO>( client, - ctx, + &mut ctx.wallet, &args.tx, - addr, - pk.clone(), - &mut tx, + &Some(args.addr.clone()), + default_signer, + ) + .await?; + + let mut tx = tx::build_update_account::<_, IO>( + client, + args.clone(), + &signing_data.gas_payer, ) .await?; - signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx).await?; + + signing::generate_test_vector::<_, _, IO>(client, &mut ctx.wallet, &tx) + .await; + + if args.tx.dump_tx { + tx::dump_tx::(&args.tx, tx); + } else { + signing::sign_tx(&mut ctx.wallet, &args.tx, &mut tx, signing_data); + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx) + .await?; + } + Ok(()) } @@ -141,23 +184,33 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, pk) = tx::build_init_account::<_, _, IO>( + let signing_data = signing::aux_signing_data::<_, _, IO>( client, &mut ctx.wallet, - args.clone(), + &args.tx, + &None, + None, ) .await?; - submit_reveal_aux::<_, IO>( + + let mut tx = tx::build_init_account::<_, IO>( client, - ctx, - &args.tx, - addr, - pk.clone(), - &mut tx, + args.clone(), + &signing_data.gas_payer, ) .await?; - signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx).await?; + + signing::generate_test_vector::<_, _, IO>(client, &mut ctx.wallet, &tx) + .await; + + if args.tx.dump_tx { + tx::dump_tx::(&args.tx, tx); + } else { + signing::sign_tx(&mut ctx.wallet, &args.tx, &mut tx, signing_data); + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx) + .await?; + } + Ok(()) } @@ -166,9 +219,9 @@ pub async fn submit_init_validator( mut ctx: Context, args::TxInitValidator { tx: tx_args, - source, scheme, - account_key, + account_keys, + threshold, consensus_key, eth_cold_key, eth_hot_key, @@ -199,25 +252,19 @@ where let validator_key_alias = format!("{}-key", alias); let consensus_key_alias = format!("{}-consensus-key", alias); + + let threshold = match threshold { + Some(threshold) => threshold, + None => { + if account_keys.len() == 1 { + 1u8 + } else { + safe_exit(1) + } + } + }; let eth_hot_key_alias = format!("{}-eth-hot-key", alias); let eth_cold_key_alias = format!("{}-eth-cold-key", alias); - let account_key = account_key.unwrap_or_else(|| { - display_line!(IO, "Generating validator account key..."); - let password = - read_and_confirm_encryption_password(unsafe_dont_encrypt); - ctx.wallet - .gen_key( - scheme, - Some(validator_key_alias.clone()), - tx_args.wallet_alias_force, - password, - None, - ) - .expect("Key generation should not fail.") - .expect("No existing alias expected.") - .1 - .ref_to() - }); let consensus_key = consensus_key .map(|key| match key { @@ -352,12 +399,14 @@ 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 mut tx = Tx::new(chain_id, tx_args.expiration); + let extra_section_hash = + tx.add_extra_section_from_hash(validator_vp_code_hash); + let data = InitValidator { - account_key, + account_keys, + threshold, consensus_key: consensus_key.ref_to(), eth_cold_key: key::secp256k1::PublicKey::try_from_pk(ð_cold_pk) .unwrap(), @@ -367,110 +416,128 @@ 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, pk) = tx::prepare_tx::<_, _, IO>( + tx.add_code_from_hash(tx_code_hash).add_data(data); + + let signing_data = signing::aux_signing_data::<_, _, IO>( client, &mut ctx.wallet, &tx_args, - tx, - TxSigningKey::WalletAddress(source), - #[cfg(not(feature = "mainnet"))] - false, + &None, + None, ) .await?; - submit_reveal_aux::<_, IO>( + + tx::prepare_tx::<_, IO>( client, - &mut ctx, &tx_args, - addr, - pk.clone(), &mut tx, + signing_data.gas_payer.clone(), + #[cfg(not(feature = "mainnet"))] + false, ) - .await?; - signing::sign_tx(&mut ctx.wallet, &mut tx, &tx_args, &pk).await?; - let result = - tx::process_tx::<_, _, IO>(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 { + .await; + + signing::generate_test_vector::<_, _, IO>(client, &mut ctx.wallet, &tx) + .await; + + if tx_args.dump_tx { + tx::dump_tx::(&tx_args, tx); + } else { + signing::sign_tx(&mut ctx.wallet, &tx_args, &mut tx, signing_data); + + let result = + tx::process_tx::<_, _, IO>(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 { + edisplay_line!( + IO, + "Expected one account to be created" + ); + safe_exit(1) + } + } + _ => { edisplay_line!(IO, "Expected one account to be created"); safe_exit(1) } - } - _ => { - edisplay_line!(IO, "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| edisplay_line!(IO, "{}", 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| edisplay_line!(IO, "{}", 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."); - display_line!(IO, ""); - display_line!( - IO, - "The validator's addresses and keys were stored in the wallet:" - ); - display_line!( - IO, - " Validator address \"{}\"", - validator_address_alias - ); - display_line!( - IO, - " Validator account key \"{}\"", - validator_key_alias - ); - display_line!(IO, " Consensus key \"{}\"", consensus_key_alias); - display_line!( - IO, - "The ledger node has been setup to use this validator's address \ - and consensus key." - ); - display_line!( - IO, - "Your validator will be active in {} epochs. Be sure to restart \ - your node for the changes to take effect!", - pos_params.pipeline_len - ); - } else { - display_line!(IO, "Transaction dry run. No addresses have been saved."); + display_line!(IO, ""); + display_line!( + IO, + "The validator's addresses and keys were stored in the wallet:" + ); + display_line!( + IO, + " Validator address \"{}\"", + validator_address_alias + ); + display_line!( + IO, + " Validator account key \"{}\"", + validator_key_alias + ); + display_line!(IO, " Consensus key \"{}\"", consensus_key_alias); + display_line!( + IO, + "The ledger node has been setup to use this validator's \ + address and consensus key." + ); + display_line!( + IO, + "Your validator will be active in {} epochs. Be sure to \ + restart your node for the changes to take effect!", + pos_params.pipeline_len + ); + } else { + display_line!( + IO, + "Transaction dry run. No addresses have been saved." + ); + } } Ok(()) } @@ -592,53 +659,73 @@ pub async fn submit_transfer( args: args::TxTransfer, ) -> Result<(), tx::Error> { for _ in 0..2 { - let arg = args.clone(); - let (mut tx, addr, pk, tx_epoch, _isf) = - tx::build_transfer::<_, _, _, IO>( - client, - &mut ctx.wallet, - &mut ctx.shielded, - arg, - ) - .await?; + let default_signer = Some(args.source.effective_address()); + let signing_data = signing::aux_signing_data::<_, _, IO>( + client, + &mut ctx.wallet, + &args.tx, + &Some(args.source.effective_address()), + default_signer, + ) + .await?; + submit_reveal_aux::<_, IO>( client, &mut ctx, - &args.tx, - addr, - pk.clone(), - &mut tx, + args.tx.clone(), + &args.source.effective_address(), ) .await?; - signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - let result = - tx::process_tx::<_, _, IO>(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::<_, IO>(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... - edisplay_line!(IO, - "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, + + let arg = args.clone(); + let (mut tx, tx_epoch) = tx::build_transfer::<_, _, IO>( + client, + &mut ctx.shielded, + arg, + &signing_data.gas_payer, + ) + .await?; + signing::generate_test_vector::<_, _, IO>(client, &mut ctx.wallet, &tx) + .await; + + if args.tx.dump_tx { + tx::dump_tx::(&args.tx, tx); + } else { + signing::sign_tx(&mut ctx.wallet, &args.tx, &mut tx, signing_data); + let result = tx::process_tx::<_, _, IO>( + client, + &mut ctx.wallet, + &args.tx, + tx, + ) + .await?; + + let submission_epoch = + rpc::query_and_print_epoch::<_, IO>(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... + edisplay_line!(IO, + "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(()) } @@ -651,23 +738,36 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, pk) = tx::build_ibc_transfer::<_, _, IO>( + let default_signer = Some(args.source.clone()); + let signing_data = signing::aux_signing_data::<_, _, IO>( client, &mut ctx.wallet, - args.clone(), + &args.tx, + &Some(args.source.clone()), + default_signer, ) .await?; - submit_reveal_aux::<_, IO>( + + submit_reveal_aux::<_, IO>(client, &mut ctx, args.tx.clone(), &args.source) + .await?; + + let mut tx = tx::build_ibc_transfer::<_, IO>( client, - &mut ctx, - &args.tx, - addr, - pk.clone(), - &mut tx, + args.clone(), + &signing_data.gas_payer, ) .await?; - signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx).await?; + signing::generate_test_vector::<_, _, IO>(client, &mut ctx.wallet, &tx) + .await; + + if args.tx.dump_tx { + tx::dump_tx::(&args.tx, tx); + } else { + signing::sign_tx(&mut ctx.wallet, &args.tx, &mut tx, signing_data); + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx) + .await?; + } + Ok(()) } @@ -680,195 +780,181 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let file = File::open(&args.proposal_data).expect("File must exist."); - let proposal: Proposal = - serde_json::from_reader(file).expect("JSON was not well-formatted"); - - let signer = WalletAddress::new(proposal.clone().author.to_string()); let current_epoch = rpc::query_and_print_epoch::<_, IO>(client).await; + let governance_parameters = rpc::query_governance_parameters(client).await; - let governance_parameters = rpc::get_governance_parameters(client).await; - if proposal.voting_start_epoch <= current_epoch - || proposal.voting_start_epoch.0 - % governance_parameters.min_proposal_period - != 0 - { - display_line!(IO, "{}", proposal.voting_start_epoch <= current_epoch); - display_line!( - IO, - "{}", - proposal.voting_start_epoch.0 - % governance_parameters.min_proposal_period - == 0 - ); - edisplay_line!( - IO, - "Invalid proposal start epoch: {} must be greater than current \ - epoch {} and a multiple of {}", - proposal.voting_start_epoch, - current_epoch, - governance_parameters.min_proposal_period - ); - if !args.tx.force { - safe_exit(1) - } - } else if proposal.voting_end_epoch <= proposal.voting_start_epoch - || proposal.voting_end_epoch.0 - proposal.voting_start_epoch.0 - < governance_parameters.min_proposal_period - || proposal.voting_end_epoch.0 - proposal.voting_start_epoch.0 - > governance_parameters.max_proposal_period - || proposal.voting_end_epoch.0 % 3 != 0 - { - edisplay_line!( - IO, - "Invalid proposal end epoch: difference between proposal start \ - and end epoch must be at least {} and at max {} and end epoch \ - must be a multiple of {}", - governance_parameters.min_proposal_period, - governance_parameters.max_proposal_period, - governance_parameters.min_proposal_period - ); - if !args.tx.force { - safe_exit(1) - } - } else if proposal.grace_epoch <= proposal.voting_end_epoch - || proposal.grace_epoch.0 - proposal.voting_end_epoch.0 - < governance_parameters.min_proposal_grace_epochs - { - edisplay_line!( - IO, - "Invalid proposal grace epoch: difference between proposal grace \ - and end epoch must be at least {}", - governance_parameters.min_proposal_grace_epochs - ); - if !args.tx.force { - safe_exit(1) - } - } - - if args.offline { - let signer = ctx.get(&signer); - let key = find_pk::<_, _, IO>(client, &mut ctx.wallet, &signer).await?; - let signing_key = - signing::find_key_by_pk(&mut ctx.wallet, &args.tx, &key)?; - let offline_proposal = - OfflineProposal::new(proposal, signer, &signing_key); - let proposal_filename = args - .proposal_data - .parent() - .expect("No parent found") - .join("proposal"); - let out = File::create(&proposal_filename).unwrap(); - match serde_json::to_writer_pretty(out, &offline_proposal) { - Ok(_) => { - display_line!( - IO, - "Proposal created: {}.", - proposal_filename.to_string_lossy() - ); - } - Err(e) => { - edisplay_line!( - IO, - "Error while creating proposal file: {}.", - e - ); - safe_exit(1) - } - } - Ok(()) - } else { - let signer = ctx.get(&signer); - let tx_data = proposal.clone().try_into(); - let (mut init_proposal_data, init_proposal_content, init_proposal_code) = - if let Ok(data) = tx_data { - data - } else { - edisplay_line!( - IO, - "Invalid data for init proposal transaction." - ); - safe_exit(1) - }; + let (mut tx_builder, signing_data) = if args.is_offline { + let proposal = namada::core::ledger::governance::cli::offline::OfflineProposal::try_from(args.proposal_data.as_ref()).map_err(|e| tx::Error::FailedGovernaneProposalDeserialize(e.to_string()))?.validate(current_epoch) + .map_err(|e| tx::Error::InvalidProposal(e.to_string()))?; - let balance = - rpc::get_token_balance(client, &ctx.native_token, &proposal.author) - .await; - if balance - < token::Amount::from_uint( - governance_parameters.min_proposal_fund, - 0, - ) - .unwrap() - { - edisplay_line!( - IO, - "Address {} doesn't have enough funds.", - &proposal.author - ); - safe_exit(1); - } + let default_signer = Some(proposal.author.clone()); + let signing_data = signing::aux_signing_data::<_, _, IO>( + client, + &mut ctx.wallet, + &args.tx, + &Some(proposal.author.clone()), + default_signer, + ) + .await?; - if init_proposal_content.len() - > governance_parameters.max_proposal_content_size as usize - { - edisplay_line!(IO, "Proposal content size too big."); - safe_exit(1); - } + let signed_offline_proposal = proposal.sign( + args.tx.signing_keys, + &signing_data.account_public_keys_map.unwrap(), + ); + let output_file_path = signed_offline_proposal + .serialize(args.tx.output_folder) + .map_err(|e| { + tx::Error::FailedGovernaneProposalDeserialize(e.to_string()) + })?; + + display_line!(IO, "Proposal serialized to: {}", output_file_path); + return Ok(()); + } else if args.is_pgf_funding { + let proposal = + PgfFundingProposal::try_from(args.proposal_data.as_ref()) + .map_err(|e| { + tx::Error::FailedGovernaneProposalDeserialize(e.to_string()) + })? + .validate(&governance_parameters, current_epoch) + .map_err(|e| tx::Error::InvalidProposal(e.to_string()))?; + + let default_signer = Some(proposal.proposal.author.clone()); + let signing_data = signing::aux_signing_data::<_, _, IO>( + client, + &mut ctx.wallet, + &args.tx, + &Some(proposal.proposal.author.clone()), + default_signer, + ) + .await?; - let mut tx = Tx::new(TxType::Raw); - let tx_code_hash = - query_wasm_code_hash::<_, IO>(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)); + submit_reveal_aux::<_, IO>( + client, + &mut ctx, + args.tx.clone(), + &proposal.proposal.author, + ) + .await?; - let (mut tx, addr, pk) = tx::prepare_tx::<_, _, IO>( + ( + tx::build_pgf_funding_proposal::<_, IO>( + client, + args.clone(), + proposal, + &signing_data.gas_payer, + ) + .await?, + signing_data, + ) + } else if args.is_pgf_stewards { + let proposal = PgfStewardProposal::try_from( + args.proposal_data.as_ref(), + ) + .map_err(|e| { + tx::Error::FailedGovernaneProposalDeserialize(e.to_string()) + })?; + let author_balane = rpc::get_token_balance( + client, + &ctx.native_token, + &proposal.proposal.author, + ) + .await; + let proposal = proposal + .validate(&governance_parameters, current_epoch, author_balane) + .map_err(|e| tx::Error::InvalidProposal(e.to_string()))?; + + let default_signer = Some(proposal.proposal.author.clone()); + let signing_data = signing::aux_signing_data::<_, _, IO>( client, &mut ctx.wallet, &args.tx, - tx, - TxSigningKey::WalletAddress(signer), - #[cfg(not(feature = "mainnet"))] - false, + &Some(proposal.proposal.author.clone()), + default_signer, ) .await?; + submit_reveal_aux::<_, IO>( client, &mut ctx, + args.tx.clone(), + &proposal.proposal.author, + ) + .await?; + + ( + tx::build_pgf_stewards_proposal::<_, IO>( + client, + args.clone(), + proposal, + &signing_data.gas_payer, + ) + .await?, + signing_data, + ) + } else { + let proposal = DefaultProposal::try_from(args.proposal_data.as_ref()) + .map_err(|e| { + tx::Error::FailedGovernaneProposalDeserialize(e.to_string()) + })?; + let author_balane = rpc::get_token_balance( + client, + &ctx.native_token, + &proposal.proposal.author, + ) + .await; + let proposal = proposal + .validate(&governance_parameters, current_epoch, author_balane) + .map_err(|e| tx::Error::InvalidProposal(e.to_string()))?; + + let default_signer = Some(proposal.proposal.author.clone()); + let signing_data = signing::aux_signing_data::<_, _, IO>( + client, + &mut ctx.wallet, &args.tx, - addr, - pk.clone(), - &mut tx, + &Some(proposal.proposal.author.clone()), + default_signer, + ) + .await?; + + submit_reveal_aux::<_, IO>( + client, + &mut ctx, + args.tx.clone(), + &proposal.proposal.author, + ) + .await?; + + ( + tx::build_default_proposal::<_, IO>( + client, + args.clone(), + proposal, + &signing_data.gas_payer, + ) + .await?, + signing_data, + ) + }; + + if args.tx.dump_tx { + tx::dump_tx::(&args.tx, tx_builder); + } else { + signing::sign_tx( + &mut ctx.wallet, + &args.tx, + &mut tx_builder, + signing_data, + ); + tx::process_tx::<_, _, IO>( + client, + &mut ctx.wallet, + &args.tx, + tx_builder, ) .await?; - signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx) - .await?; - Ok(()) } + + Ok(()) } pub async fn submit_vote_proposal( @@ -880,293 +966,174 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let signer = if let Some(addr) = &args.tx.signer { - addr - } else { - edisplay_line!(IO, "Missing mandatory argument --signer."); - safe_exit(1) - }; - - // Construct vote - let proposal_vote = match args.vote.to_ascii_lowercase().as_str() { - "yay" => { - if let Some(pgf) = args.proposal_pgf { - let splits = pgf.trim().split_ascii_whitespace(); - let address_iter = splits.clone().step_by(2); - let cap_iter = splits.into_iter().skip(1).step_by(2); - let mut set = HashSet::new(); - for (address, cap) in - address_iter.zip(cap_iter).map(|(addr, cap)| { - ( - addr.parse() - .expect("Failed to parse pgf council address"), - cap.parse::() - .expect("Failed to parse pgf spending cap"), - ) - }) - { - set.insert(( - address, - token::Amount::from_uint(cap, 0).unwrap(), - )); - } - - ProposalVote::Yay(VoteType::PGFCouncil(set)) - } else if let Some(eth) = args.proposal_eth { - let mut splits = eth.trim().split_ascii_whitespace(); - // Sign the message - let sigkey = splits - .next() - .expect("Expected signing key") - .parse::() - .expect("Signing key parsing failed."); - - let msg = splits.next().expect("Missing message to sign"); - if splits.next().is_some() { - edisplay_line!(IO, "Unexpected argument after message"); - safe_exit(1); - } + let current_epoch = rpc::query_and_print_epoch::<_, IO>(client).await; - ProposalVote::Yay(VoteType::ETHBridge(common::SigScheme::sign( - &sigkey, - HEXLOWER_PERMISSIVE - .decode(msg.as_bytes()) - .expect("Error while decoding message"), - ))) - } else { - ProposalVote::Yay(VoteType::Default) - } - } - "nay" => ProposalVote::Nay, - _ => { - edisplay_line!(IO, "Vote must be either yay or nay"); - safe_exit(1); - } - }; + let default_signer = Some(args.voter.clone()); + let signing_data = signing::aux_signing_data::<_, _, IO>( + client, + &mut ctx.wallet, + &args.tx, + &Some(args.voter.clone()), + default_signer.clone(), + ) + .await?; - if args.offline { - if !proposal_vote.is_default_vote() { - edisplay_line!( - IO, - "Wrong vote type for offline proposal. Just vote yay or nay!" - ); - safe_exit(1); - } - let proposal_file_path = - args.proposal_data.expect("Proposal file should exist."); - let file = File::open(&proposal_file_path).expect("File must exist."); + let mut tx_builder = if args.is_offline { + let proposal_vote = ProposalVote::try_from(args.vote) + .map_err(|_| tx::Error::InvalidProposalVote)?; - let proposal: OfflineProposal = - serde_json::from_reader(file).expect("JSON was not well-formatted"); - let public_key = rpc::get_public_key(client, &proposal.address) - .await - .expect("Public key should exist."); - if !proposal.check_signature(&public_key) { - edisplay_line!(IO, "Proposal signature mismatch!"); - safe_exit(1) - } + let proposal = OfflineSignedProposal::try_from( + args.proposal_data.clone().unwrap().as_ref(), + ) + .map_err(|e| tx::Error::InvalidProposal(e.to_string()))? + .validate( + &signing_data.account_public_keys_map.clone().unwrap(), + signing_data.threshold, + ) + .map_err(|e| tx::Error::InvalidProposal(e.to_string()))?; + let delegations = rpc::get_delegators_delegation_at( + client, + &args.voter, + proposal.proposal.tally_epoch, + ) + .await + .keys() + .cloned() + .collect::>(); - let key = find_pk::<_, _, IO>(client, &mut ctx.wallet, signer).await?; - let signing_key = - signing::find_key_by_pk(&mut ctx.wallet, &args.tx, &key)?; let offline_vote = OfflineVote::new( &proposal, proposal_vote, - signer.clone(), - &signing_key, + args.voter.clone(), + delegations, ); - let proposal_vote_filename = proposal_file_path - .parent() - .expect("No parent found") - .join(format!("proposal-vote-{}", &signer.to_string())); - let out = File::create(&proposal_vote_filename).unwrap(); - match serde_json::to_writer_pretty(out, &offline_vote) { - Ok(_) => { - display_line!( - IO, - "Proposal vote created: {}.", - proposal_vote_filename.to_string_lossy() - ); - Ok(()) - } - Err(e) => { - edisplay_line!( - IO, - "Error while creating proposal vote file: {}.", - e - ); - safe_exit(1) - } - } + let offline_signed_vote = offline_vote.sign( + args.tx.signing_keys, + &signing_data.account_public_keys_map.unwrap(), + ); + let output_file_path = offline_signed_vote + .serialize(args.tx.output_folder) + .expect("Should be able to serialize the offline proposal"); + + display_line!(IO, "Proposal vote serialized to: {}", output_file_path); + return Ok(()); } else { - let current_epoch = rpc::query_and_print_epoch::<_, IO>(client).await; + tx::build_vote_proposal::<_, IO>( + client, + args.clone(), + current_epoch, + &signing_data.gas_payer, + ) + .await? + }; - let voter_address = signer.clone(); - let proposal_id = args.proposal_id.unwrap(); - let proposal_start_epoch_key = - gov_storage::get_voting_start_epoch_key(proposal_id); - let proposal_start_epoch = rpc::query_storage_value::( + if args.tx.dump_tx { + tx::dump_tx::(&args.tx, tx_builder); + } else { + signing::sign_tx( + &mut ctx.wallet, + &args.tx, + &mut tx_builder, + signing_data, + ); + tx::process_tx::<_, _, IO>( client, - &proposal_start_epoch_key, + &mut ctx.wallet, + &args.tx, + tx_builder, ) - .await; + .await?; + } - // Check vote type and memo - let proposal_type_key = gov_storage::get_proposal_type_key(proposal_id); - let proposal_type: ProposalType = rpc::query_storage_value::< - C, - ProposalType, - >(client, &proposal_type_key) - .await - .unwrap_or_else(|| { - panic!("Didn't find type of proposal id {} in storage", proposal_id) - }); + Ok(()) +} + +pub async fn sign_tx( + client: &C, + ctx: &mut Context, + args::SignTx { + tx: tx_args, + tx_data, + owner, + }: args::SignTx, +) -> Result<(), tx::Error> +where + C: namada::ledger::queries::Client + Sync, + C::Error: std::fmt::Display, +{ + let tx = if let Ok(transaction) = Tx::deserialize(tx_data.as_ref()) { + transaction + } else { + edisplay_line!(IO, "Couldn't decode the transaction."); + safe_exit(1) + }; + + let default_signer = Some(owner.clone()); + let signing_data = signing::aux_signing_data::<_, _, IO>( + client, + &mut ctx.wallet, + &tx_args, + &Some(owner), + default_signer, + ) + .await?; - if let ProposalVote::Yay(ref vote_type) = proposal_vote { - if &proposal_type != vote_type { + let secret_keys = &signing_data + .public_keys + .iter() + .filter_map(|public_key| { + if let Ok(secret_key) = + signing::find_key_by_pk(&mut ctx.wallet, &tx_args, public_key) + { + Some(secret_key) + } else { edisplay_line!( IO, - "Expected vote of type {}, found {}", - proposal_type, - args.vote + "Couldn't find the secret key for {}. Skipping signature \ + generation.", + public_key ); - safe_exit(1); - } else if let VoteType::PGFCouncil(set) = vote_type { - // Check that addresses proposed as council are established and - // are present in storage - for (address, _) in set { - match address { - Address::Established(_) => { - let vp_key = Key::validity_predicate(address); - if !rpc::query_has_storage_key::(client, &vp_key) - .await - { - edisplay_line!( - IO, - "Proposed PGF council {} cannot be found \ - in storage", - address - ); - safe_exit(1); - } - } - _ => { - edisplay_line!( - IO, - "PGF council vote contains a non-established \ - address: {}", - address - ); - safe_exit(1); - } - } - } + None } - } + }) + .collect::>(); - match proposal_start_epoch { - Some(epoch) => { - if current_epoch < epoch { - edisplay_line!( - IO, - "Current epoch {} is not greater than proposal start \ - epoch {}", - current_epoch, - epoch - ); + if let Some(account_public_keys_map) = signing_data.account_public_keys_map + { + let signatures = + tx.compute_section_signature(secret_keys, &account_public_keys_map); + + for signature in &signatures { + let filename = format!( + "offline_signature_{}_{}.tx", + tx.header_hash(), + signature.index + ); + let output_path = match &tx_args.output_folder { + Some(path) => path.join(filename), + None => filename.into(), + }; - if !args.tx.force { - safe_exit(1) - } - } - let mut delegations = - rpc::get_delegators_delegation(client, &voter_address) - .await; - - // Optimize by quering if a vote from a validator - // is equal to ours. If so, we can avoid voting, but ONLY if we - // are voting in the last third of the voting - // window, otherwise there's the risk of the - // validator changing his vote and, effectively, invalidating - // the delgator's vote - if !args.tx.force - && is_safe_voting_window(client, proposal_id, epoch).await? - { - delegations = filter_delegations( - client, - delegations, - proposal_id, - &proposal_vote, - ) - .await; - } + let signature_path = File::create(&output_path) + .expect("Should be able to create signature file."); - let tx_data = VoteProposalData { - id: proposal_id, - vote: proposal_vote, - voter: voter_address, - 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::<_, IO>( - 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, pk) = tx::prepare_tx::<_, _, IO>( - client, - &mut ctx.wallet, - &args.tx, - tx, - TxSigningKey::WalletAddress(signer.clone()), - #[cfg(not(feature = "mainnet"))] - false, - ) - .await?; - submit_reveal_aux::<_, IO>( - client, - &mut ctx, - &args.tx, - addr, - pk.clone(), - &mut tx, - ) - .await?; - signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk) - .await?; - tx::process_tx::<_, _, IO>( - client, - &mut ctx.wallet, - &args.tx, - tx, - ) - .await?; - Ok(()) - } - None => { - edisplay_line!( - IO, - "Proposal start epoch for proposal id {} is not definied.", - proposal_id - ); - if !args.tx.force { safe_exit(1) } else { Ok(()) } - } + serde_json::to_writer_pretty( + signature_path, + &signature.serialize(), + ) + .expect("Signature should be deserializable."); + display_line!( + IO, + "Signature for {} serialized at {}", + &account_public_keys_map + .get_public_key_from_index(signature.index) + .unwrap(), + output_path.display() + ); } } + Ok(()) } pub async fn submit_reveal_pk( @@ -1178,73 +1145,15 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let reveal_tx = - tx::build_reveal_pk::<_, _, IO>(client, &mut ctx.wallet, args.clone()) - .await?; - if let Some((mut tx, _, pk)) = reveal_tx { - signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx) - .await?; - } - Ok(()) -} - -/// Check if current epoch is in the last third of the voting period of the -/// proposal. This ensures that it is safe to optimize the vote writing to -/// storage. -async fn is_safe_voting_window( - client: &C, - proposal_id: u64, - proposal_start_epoch: Epoch, -) -> Result -where - C: namada::ledger::queries::Client + Sync, - C::Error: std::fmt::Display, -{ - tx::is_safe_voting_window(client, proposal_id, proposal_start_epoch).await -} - -/// Removes validators whose vote corresponds to that of the delegator (needless -/// vote) -async fn filter_delegations( - client: &C, - delegations: HashSet
, - proposal_id: u64, - delegator_vote: &ProposalVote, -) -> HashSet
-where - C: namada::ledger::queries::Client + Sync, - C::Error: std::fmt::Display, -{ - // Filter delegations by their validator's vote concurrently - let delegations = futures::future::join_all( - delegations - .into_iter() - // we cannot use `filter/filter_map` directly because we want to - // return a future - .map(|validator_address| async { - let vote_key = gov_storage::get_vote_proposal_key( - proposal_id, - validator_address.to_owned(), - validator_address.to_owned(), - ); - - if let Some(validator_vote) = - rpc::query_storage_value::( - client, &vote_key, - ) - .await - { - if &validator_vote == delegator_vote { - return None; - } - } - Some(validator_address) - }), + submit_reveal_aux::<_, IO>( + client, + ctx, + args.tx, + &(&args.public_key).into(), ) - .await; - // Take out the `None`s - delegations.into_iter().flatten().collect() + .await?; + + Ok(()) } pub async fn submit_bond( @@ -1256,20 +1165,35 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, pk) = - tx::build_bond::(client, &mut ctx.wallet, args.clone()) - .await?; - submit_reveal_aux::<_, IO>( + let default_address = args.source.clone().unwrap_or(args.validator.clone()); + let default_signer = Some(default_address.clone()); + let signing_data = signing::aux_signing_data::<_, _, IO>( client, - ctx, + &mut ctx.wallet, &args.tx, - addr, - pk.clone(), - &mut tx, + &Some(default_address.clone()), + default_signer, ) .await?; - signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx).await?; + + submit_reveal_aux::<_, IO>(client, ctx, args.tx.clone(), &default_address) + .await?; + + let mut tx = + tx::build_bond::(client, args.clone(), &signing_data.gas_payer) + .await?; + signing::generate_test_vector::<_, _, IO>(client, &mut ctx.wallet, &tx) + .await; + + if args.tx.dump_tx { + tx::dump_tx::(&args.tx, tx); + } else { + signing::sign_tx(&mut ctx.wallet, &args.tx, &mut tx, signing_data); + + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx) + .await?; + } + Ok(()) } @@ -1282,22 +1206,39 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, pk, latest_withdrawal_pre) = - tx::build_unbond::<_, _, IO>(client, &mut ctx.wallet, args.clone()) - .await?; - submit_reveal_aux::<_, IO>( + let default_address = args.source.clone().unwrap_or(args.validator.clone()); + let default_signer = Some(default_address.clone()); + let signing_data = signing::aux_signing_data::<_, _, IO>( client, - ctx, + &mut ctx.wallet, &args.tx, - addr, - pk.clone(), - &mut tx, + &Some(default_address), + default_signer, ) .await?; - signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx).await?; - tx::query_unbonds::<_, IO>(client, args.clone(), latest_withdrawal_pre) - .await?; + + let (mut tx, latest_withdrawal_pre) = tx::build_unbond::<_, _, IO>( + client, + &mut ctx.wallet, + args.clone(), + &signing_data.gas_payer, + ) + .await?; + signing::generate_test_vector::<_, _, IO>(client, &mut ctx.wallet, &tx) + .await; + + if args.tx.dump_tx { + tx::dump_tx::(&args.tx, tx); + } else { + signing::sign_tx(&mut ctx.wallet, &args.tx, &mut tx, signing_data); + + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx) + .await?; + + tx::query_unbonds::<_, IO>(client, args.clone(), latest_withdrawal_pre) + .await?; + } + Ok(()) } @@ -1310,20 +1251,35 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, pk) = - tx::build_withdraw::<_, _, IO>(client, &mut ctx.wallet, args.clone()) - .await?; - submit_reveal_aux::<_, IO>( + let default_address = args.source.clone().unwrap_or(args.validator.clone()); + let default_signer = Some(default_address.clone()); + let signing_data = signing::aux_signing_data::<_, _, IO>( client, - &mut ctx, + &mut ctx.wallet, &args.tx, - addr, - pk.clone(), - &mut tx, + &Some(default_address), + default_signer, ) .await?; - signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx).await?; + + let mut tx = tx::build_withdraw::<_, IO>( + client, + args.clone(), + &signing_data.gas_payer, + ) + .await?; + signing::generate_test_vector::<_, _, IO>(client, &mut ctx.wallet, &tx) + .await; + + if args.tx.dump_tx { + tx::dump_tx::(&args.tx, tx); + } else { + signing::sign_tx(&mut ctx.wallet, &args.tx, &mut tx, signing_data); + + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx) + .await?; + } + Ok(()) } @@ -1336,24 +1292,34 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let arg = args.clone(); - let (mut tx, addr, pk) = tx::build_validator_commission_change::<_, _, IO>( + let default_signer = Some(args.validator.clone()); + let signing_data = signing::aux_signing_data::<_, _, IO>( client, &mut ctx.wallet, - arg, + &args.tx, + &Some(args.validator.clone()), + default_signer, ) .await?; - submit_reveal_aux::<_, IO>( + + let mut tx = tx::build_validator_commission_change::<_, IO>( client, - &mut ctx, - &args.tx, - addr, - pk.clone(), - &mut tx, + args.clone(), + &signing_data.gas_payer, ) .await?; - signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx).await?; + signing::generate_test_vector::<_, _, IO>(client, &mut ctx.wallet, &tx) + .await; + + if args.tx.dump_tx { + tx::dump_tx::(&args.tx, tx); + } else { + signing::sign_tx(&mut ctx.wallet, &args.tx, &mut tx, signing_data); + + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx) + .await?; + } + Ok(()) } @@ -1369,23 +1335,34 @@ where C: namada::ledger::queries::Client + Sync, C::Error: std::fmt::Display, { - let (mut tx, addr, pk) = tx::build_unjail_validator::<_, _, IO>( + let default_signer = Some(args.validator.clone()); + let signing_data = signing::aux_signing_data::<_, _, IO>( client, &mut ctx.wallet, - args.clone(), + &args.tx, + &Some(args.validator.clone()), + default_signer, ) .await?; - submit_reveal_aux::<_, IO>( + + let mut tx = tx::build_unjail_validator::<_, IO>( client, - &mut ctx, - &args.tx, - addr, - pk.clone(), - &mut tx, + args.clone(), + &signing_data.gas_payer, ) .await?; - signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; - tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx).await?; + signing::generate_test_vector::<_, _, IO>(client, &mut ctx.wallet, &tx) + .await; + + if args.tx.dump_tx { + tx::dump_tx::(&args.tx, tx); + } else { + signing::sign_tx(&mut ctx.wallet, &args.tx, &mut tx, signing_data); + + tx::process_tx::<_, _, IO>(client, &mut ctx.wallet, &args.tx, tx) + .await?; + } + Ok(()) } @@ -1436,12 +1413,11 @@ where #[cfg(test)] mod test_tx { use masp_primitives::transaction::components::Amount; + use namada::core::types::storage::Epoch; use namada::ledger::masp::{make_asset_type, MaspAmount}; use namada::types::address::testing::gen_established_address; use namada::types::token::MaspDenom; - use super::*; - #[test] fn test_masp_add_amount() { let address_1 = gen_established_address(); diff --git a/apps/src/lib/config/genesis.rs b/apps/src/lib/config/genesis.rs index 5c86debcb6..e9abf6c26d 100644 --- a/apps/src/lib/config/genesis.rs +++ b/apps/src/lib/config/genesis.rs @@ -4,10 +4,11 @@ use std::collections::HashMap; use borsh::{BorshDeserialize, BorshSerialize}; use derivative::Derivative; +use namada::core::ledger::governance::parameters::GovernanceParameters; +use namada::core::ledger::pgf::parameters::PgfParameters; #[cfg(not(feature = "mainnet"))] use namada::core::ledger::testnet_pow; use namada::ledger::eth_bridge::EthereumBridgeConfig; -use namada::ledger::governance::parameters::GovParams; use namada::ledger::parameters::EpochDuration; use namada::ledger::pos::{Dec, GenesisValidator, PosParams}; use namada::types::address::Address; @@ -22,16 +23,17 @@ use namada::types::{storage, token}; /// Genesis configuration file format pub mod genesis_config { use std::array::TryFromSliceError; - use std::collections::HashMap; + use std::collections::{BTreeSet, HashMap}; use std::convert::TryInto; use std::path::Path; use std::str::FromStr; use data_encoding::HEXLOWER; use eyre::Context; + use namada::core::ledger::governance::parameters::GovernanceParameters; + use namada::core::ledger::pgf::parameters::PgfParameters; #[cfg(not(feature = "mainnet"))] use namada::core::ledger::testnet_pow; - use namada::ledger::governance::parameters::GovParams; use namada::ledger::parameters::EpochDuration; use namada::ledger::pos::{Dec, GenesisValidator, PosParams}; use namada::types::address::Address; @@ -135,6 +137,8 @@ pub mod genesis_config { pub pos_params: PosParamsConfig, // Governance parameters pub gov_params: GovernanceParamsConfig, + // Pgf parameters + pub pgf_params: PgfParametersConfig, // Ethereum bridge config pub ethereum_bridge_params: Option, // Wasm definitions @@ -148,7 +152,7 @@ pub mod genesis_config { // Maximum size of proposal in kibibytes (KiB) pub max_proposal_code_size: u64, // Minimum proposal period length in epochs - pub min_proposal_period: u64, + pub min_proposal_voting_period: u64, // Maximum proposal period length in epochs pub max_proposal_period: u64, // Maximum number of characters in the proposal content @@ -157,6 +161,16 @@ pub mod genesis_config { pub min_proposal_grace_epochs: u64, } + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct PgfParametersConfig { + /// The set of stewards + pub stewards: BTreeSet
, + /// The pgf inflation rate + pub pgf_inflation_rate: Dec, + /// The stewards inflation rate + pub stewards_inflation_rate: Dec, + } + /// Validator pre-genesis configuration can be created with client utils /// `init-genesis-validator` command and added to a genesis for /// `init-network` cmd and that can be subsequently read by `join-network` @@ -261,6 +275,8 @@ pub mod genesis_config { pub implicit_vp: String, /// Expected number of epochs per year pub epochs_per_year: u64, + /// Max signature per transaction + pub max_signatures_per_transaction: u8, /// PoS gain p pub pos_gain_p: Dec, /// PoS gain d @@ -524,6 +540,7 @@ pub mod genesis_config { parameters, pos_params, gov_params, + pgf_params, wasm, ethereum_bridge_params, } = config; @@ -601,30 +618,44 @@ pub mod genesis_config { implicit_vp_code_path, implicit_vp_sha256, epochs_per_year: parameters.epochs_per_year, + max_signatures_per_transaction: parameters + .max_signatures_per_transaction, pos_gain_p: parameters.pos_gain_p, pos_gain_d: parameters.pos_gain_d, staked_ratio: Dec::zero(), pos_inflation_amount: token::Amount::zero(), + #[cfg(not(feature = "mainnet"))] wrapper_tx_fees: parameters.wrapper_tx_fees, }; let GovernanceParamsConfig { min_proposal_fund, max_proposal_code_size, - min_proposal_period, + min_proposal_voting_period, max_proposal_content_size, min_proposal_grace_epochs, max_proposal_period, } = gov_params; - let gov_params = GovParams { - min_proposal_fund, + let gov_params = GovernanceParameters { + min_proposal_fund: token::Amount::native_whole(min_proposal_fund), max_proposal_code_size, - min_proposal_period, + min_proposal_voting_period, max_proposal_content_size, min_proposal_grace_epochs, max_proposal_period, }; + let PgfParametersConfig { + stewards, + pgf_inflation_rate, + stewards_inflation_rate, + } = pgf_params; + let pgf_params = PgfParameters { + stewards, + pgf_inflation_rate, + stewards_inflation_rate, + }; + let PosParamsConfig { max_validator_slots, pipeline_len, @@ -639,6 +670,7 @@ pub mod genesis_config { cubic_slashing_window_length, validator_stake_threshold, } = pos_params; + let pos_params = PosParams { max_validator_slots, pipeline_len, @@ -668,6 +700,7 @@ pub mod genesis_config { parameters, pos_params, gov_params, + pgf_params, ethereum_bridge_params, }; genesis.init(); @@ -720,7 +753,8 @@ pub struct Genesis { pub implicit_accounts: Vec, pub parameters: Parameters, pub pos_params: PosParams, - pub gov_params: GovParams, + pub gov_params: GovernanceParameters, + pub pgf_params: PgfParameters, // Ethereum bridge config pub ethereum_bridge_params: Option, } @@ -848,6 +882,8 @@ pub struct Parameters { pub implicit_vp_sha256: [u8; 32], /// Expected number of epochs per year (read only) pub epochs_per_year: u64, + /// Maximum amount of signatures per transaction + pub max_signatures_per_transaction: u8, /// PoS gain p (read only) pub pos_gain_p: Dec, /// PoS gain d (read only) @@ -969,12 +1005,14 @@ pub fn genesis(num_validators: u64) -> Genesis { tx_whitelist: vec![], implicit_vp_code_path: vp_implicit_path.into(), implicit_vp_sha256: Default::default(), + max_signatures_per_transaction: 15, epochs_per_year: 525_600, /* seconds in yr (60*60*24*365) div seconds * per epoch (60 = min_duration) */ pos_gain_p: Dec::new(1, 1).expect("This can't fail"), pos_gain_d: Dec::new(1, 1).expect("This can't fail"), staked_ratio: Dec::zero(), pos_inflation_amount: token::Amount::zero(), + #[cfg(not(feature = "mainnet"))] wrapper_tx_fees: Some(token::Amount::native_whole(0)), }; let albert = EstablishedAccount { @@ -1074,7 +1112,8 @@ pub fn genesis(num_validators: u64) -> Genesis { token_accounts, parameters, pos_params: PosParams::default(), - gov_params: GovParams::default(), + gov_params: GovernanceParameters::default(), + pgf_params: PgfParameters::default(), ethereum_bridge_params: Some(EthereumBridgeConfig { eth_start_height: Default::default(), min_confirmations: Default::default(), diff --git a/apps/src/lib/config/mod.rs b/apps/src/lib/config/mod.rs index 0bcb1b5f61..f6307c6bd1 100644 --- a/apps/src/lib/config/mod.rs +++ b/apps/src/lib/config/mod.rs @@ -283,7 +283,7 @@ impl Config { .and_then(|c| c.merge(config::File::with_name(file_name))) .and_then(|c| { c.merge( - config::Environment::with_prefix("namada").separator("__"), + config::Environment::with_prefix("NAMADA").separator("__"), ) }) .map_err(Error::ReadError)?; diff --git a/apps/src/lib/node/ledger/mod.rs b/apps/src/lib/node/ledger/mod.rs index 37b447b4da..e421fc6e6b 100644 --- a/apps/src/lib/node/ledger/mod.rs +++ b/apps/src/lib/node/ledger/mod.rs @@ -14,8 +14,8 @@ use std::thread; use byte_unit::Byte; use futures::future::TryFutureExt; +use namada::core::ledger::governance::storage::keys as governance_storage; use namada::eth_bridge::ethers::providers::{Http, Provider}; -use namada::ledger::governance::storage as gov_storage; use namada::types::storage::Key; use once_cell::unsync::Lazy; use sysinfo::{RefreshKind, System, SystemExt}; @@ -64,7 +64,7 @@ const ENV_VAR_RAYON_THREADS: &str = "NAMADA_RAYON_THREADS"; //``` impl Shell { fn load_proposals(&mut self) { - let proposals_key = gov_storage::get_commiting_proposals_prefix( + let proposals_key = governance_storage::get_commiting_proposals_prefix( self.wl_storage.storage.last_epoch.0, ); @@ -73,7 +73,7 @@ impl Shell { for (key, _, _) in proposal_iter { let key = Key::from_str(key.as_str()).expect("Key should be parsable"); - if gov_storage::get_commit_proposal_epoch(&key).unwrap() + if governance_storage::get_commit_proposal_epoch(&key).unwrap() != self.wl_storage.storage.last_epoch.0 { // NOTE: `iter_prefix` iterate over the matching prefix. In this @@ -85,7 +85,7 @@ impl Shell { continue; } - let proposal_id = gov_storage::get_commit_proposal_id(&key); + let proposal_id = governance_storage::get_commit_proposal_id(&key); if let Some(id) = proposal_id { self.proposal_data.insert(id); } @@ -329,7 +329,7 @@ async fn run_aux_setup( // Find the system available memory let available_memory_bytes = Lazy::new(|| { let sys = System::new_with_specifics(RefreshKind::new().with_memory()); - let available_memory_bytes = sys.available_memory() * 1024; + let available_memory_bytes = sys.available_memory(); tracing::info!( "Available memory: {}", Byte::from_bytes(available_memory_bytes as u128) diff --git a/apps/src/lib/node/ledger/shell/finalize_block.rs b/apps/src/lib/node/ledger/shell/finalize_block.rs index 2f178eb47e..8af2d1a746 100644 --- a/apps/src/lib/node/ledger/shell/finalize_block.rs +++ b/apps/src/lib/node/ledger/shell/finalize_block.rs @@ -3,6 +3,8 @@ use std::collections::HashMap; use data_encoding::HEXUPPER; +use namada::core::ledger::pgf::storage::keys as pgf_storage; +use namada::core::ledger::pgf::ADDRESS as pgf_address; use namada::ledger::parameters::storage as params_storage; use namada::ledger::pos::{namada_proof_of_stake, staking_token_address}; use namada::ledger::storage::EPOCH_SWITCH_BLOCKS_DELAY; @@ -92,8 +94,7 @@ where &mut self.wl_storage, )?; - let _proposals_result = - execute_governance_proposals(self, &mut response)?; + execute_governance_proposals(self, &mut response)?; // Copy the new_epoch + pipeline_len - 1 validator set into // new_epoch + pipeline_len @@ -247,15 +248,15 @@ where self.invalidate_pow_solution_if_valid(wrapper); // Charge fee - let fee_payer = + let gas_payer = if wrapper.pk != address::masp_tx_key().ref_to() { - wrapper.fee_payer() + wrapper.gas_payer() } else { address::masp() }; let balance_key = - token::balance_key(&wrapper.fee.token, &fee_payer); + token::balance_key(&wrapper.fee.token, &gas_payer); let balance: token::Amount = self .wl_storage .read(&balance_key) @@ -817,6 +818,68 @@ where .remove(&mut self.wl_storage, &address)?; } + // Pgf inflation + let pgf_inflation_rate_key = pgf_storage::get_pgf_inflation_rate_key(); + let pgf_inflation_rate = self + .read_storage_key::(&pgf_inflation_rate_key) + .unwrap_or_default(); + + let pgf_pd_rate = pgf_inflation_rate / Dec::from(epochs_per_year); + let pgf_inflation = Dec::from(total_tokens) * pgf_pd_rate; + let pgf_inflation_amount = token::Amount::from(pgf_inflation); + + credit_tokens( + &mut self.wl_storage, + &staking_token, + &pgf_address, + pgf_inflation_amount, + )?; + + tracing::info!( + "Minting {} tokens for PGF rewards distribution into the PGF \ + account.", + pgf_inflation_amount.to_string_native() + ); + + // Pgf steward inflation + let pgf_stewards_inflation_rate_key = + pgf_storage::get_steward_inflation_rate_key(); + let pgf_stewards_inflation_rate = self + .read_storage_key::(&pgf_stewards_inflation_rate_key) + .unwrap_or_default(); + + let pgf_stewards_pd_rate = + pgf_stewards_inflation_rate / Dec::from(epochs_per_year); + let pgf_steward_inflation = + Dec::from(total_tokens) * pgf_stewards_pd_rate; + + let pgf_stewards_key = pgf_storage::get_stewards_key(); + let pgf_stewards: BTreeSet
= + self.read_storage_key(&pgf_stewards_key).unwrap_or_default(); + + let pgf_steward_reward = match pgf_stewards.len() { + 0 => Dec::zero(), + _ => pgf_steward_inflation + .trunc_div(&Dec::from(pgf_stewards.len())) + .unwrap_or_default(), + }; + let pgf_steward_reward = token::Amount::from(pgf_steward_reward); + + for steward in pgf_stewards { + credit_tokens( + &mut self.wl_storage, + &staking_token, + &steward, + pgf_steward_reward, + )?; + tracing::info!( + "Minting {} tokens for PGF Steward rewards distribution into \ + the steward address {}.", + pgf_steward_reward.to_string_native(), + steward, + ); + } + Ok(()) } @@ -941,6 +1004,11 @@ mod test_finalize_block { use data_encoding::HEXUPPER; use namada::core::ledger::eth_bridge::storage::wrapped_erc20s; + use namada::core::ledger::governance::storage::keys::get_proposal_execution_key; + use namada::core::ledger::governance::storage::proposal::ProposalType; + use namada::core::ledger::governance::storage::vote::{ + StorageProposalVote, VoteType, + }; use namada::eth_bridge::storage::bridge_pool::{ self, get_key_from_hash, get_nonce_key, get_signed_root_key, }; @@ -973,7 +1041,6 @@ mod test_finalize_block { use namada::types::ethereum_events::{ EthAddress, TransferToEthereum, Uint as ethUint, }; - use namada::types::governance::ProposalVote; use namada::types::hash::Hash; use namada::types::keccak::KeccakHash; use namada::types::key::tm_consensus_key_raw_hash; @@ -981,7 +1048,7 @@ mod test_finalize_block { use namada::types::time::{DateTimeUtc, DurationSecs}; use namada::types::token::{Amount, NATIVE_MAX_DECIMAL_PLACES}; use namada::types::transaction::governance::{ - InitProposalData, ProposalType, VoteProposalData, + InitProposalData, VoteProposalData, }; use namada::types::transaction::protocol::EthereumTxData; use namada::types::transaction::{Fee, WrapperTx, MIN_FEE_AMOUNT}; @@ -1007,7 +1074,7 @@ mod test_finalize_block { keypair: &common::SecretKey, ) -> (Tx, ProcessedTx) { let mut wrapper_tx = - Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( Fee { amount: MIN_FEE_AMOUNT, token: shell.wl_storage.storage.native_token.clone(), @@ -1047,17 +1114,18 @@ mod test_finalize_block { keypair: &common::SecretKey, ) -> ProcessedTx { let tx_code = TestWasms::TxNoOp.read_bytes(); - let mut outer_tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: MIN_FEE_AMOUNT, - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut outer_tx = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: MIN_FEE_AMOUNT, + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); outer_tx.header.chain_id = shell.chain_id.clone(); outer_tx.set_code(Code::new(tx_code)); outer_tx.set_data(Data::new( @@ -1155,17 +1223,18 @@ mod test_finalize_block { fn test_process_proposal_rejected_decrypted_tx() { let (mut shell, _, _, _) = setup(); let keypair = gen_keypair(); - let mut outer_tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: Default::default(), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut outer_tx = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: Default::default(), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); outer_tx.header.chain_id = shell.chain_id.clone(); outer_tx.set_code(Code::new("wasm_code".as_bytes().to_owned())); outer_tx.set_data(Data::new( @@ -1221,7 +1290,7 @@ mod test_finalize_block { pow_solution: None, }; let processed_tx = ProcessedTx { - tx: Tx::new(TxType::Decrypted(DecryptedTx::Undecryptable)) + tx: Tx::from_type(TxType::Decrypted(DecryptedTx::Undecryptable)) .to_bytes(), result: TxResult { code: ErrorCodes::Ok.into(), @@ -1229,7 +1298,7 @@ mod test_finalize_block { }, }; - let tx = Tx::new(TxType::Wrapper(Box::new(wrapper))); + let tx = Tx::from_type(TxType::Wrapper(Box::new(wrapper))); shell.enqueue_tx(tx); // check that correct error message is returned @@ -1754,11 +1823,8 @@ mod test_finalize_block { }; // Add a proposal to be accepted and one to be rejected. - add_proposal( - 0, - ProposalVote::Yay(namada::types::governance::VoteType::Default), - ); - add_proposal(1, ProposalVote::Nay); + add_proposal(0, StorageProposalVote::Yay(VoteType::Default)); + add_proposal(1, StorageProposalVote::Nay); // Commit the genesis state shell.wl_storage.commit_block().unwrap(); @@ -2189,7 +2255,7 @@ mod test_finalize_block { let tx_code = std::fs::read(wasm_path) .expect("Expected a file at given code path"); let mut wrapper_tx = - Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( Fee { amount: Amount::zero(), token: shell.wl_storage.storage.native_token.clone(), @@ -3505,16 +3571,15 @@ mod test_finalize_block { /// Test that updating the ethereum bridge params via governance works. #[tokio::test] async fn test_eth_bridge_param_updates() { - use namada::ledger::governance::storage as gov_storage; let (mut shell, _broadcaster, _, mut control_receiver) = setup_at_height(3u64); - let proposal_execution_key = gov_storage::get_proposal_execution_key(0); + let proposal_execution_key = get_proposal_execution_key(0); shell .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 mut tx = Tx::new(shell.chain_id.clone(), None); + tx.add_code_from_hash(Hash::default()).add_data(0u64); let new_min_confirmations = MinimumConfirmations::from(unsafe { NonZeroU64::new_unchecked(42) }); diff --git a/apps/src/lib/node/ledger/shell/governance.rs b/apps/src/lib/node/ledger/shell/governance.rs index e488cbf2b8..09f0c9dac3 100644 --- a/apps/src/lib/node/ledger/shell/governance.rs +++ b/apps/src/lib/node/ledger/shell/governance.rs @@ -1,22 +1,30 @@ -use namada::core::ledger::slash_fund::ADDRESS as slash_fund_address; -use namada::core::types::transaction::governance::ProposalType; -use namada::ledger::events::EventType; -use namada::ledger::governance::{ - storage as gov_storage, ADDRESS as gov_address, +use std::collections::{BTreeSet, HashMap}; + +use namada::core::ledger::governance::storage::keys as gov_storage; +use namada::core::ledger::governance::storage::proposal::{ + AddRemove, PGFAction, PGFTarget, ProposalType, }; -use namada::ledger::native_vp::governance::utils::{ - compute_tally, get_proposal_votes, ProposalEvent, +use namada::core::ledger::governance::utils::{ + compute_proposal_result, ProposalVotes, TallyResult, TallyType, TallyVote, + VotePower, }; +use namada::core::ledger::governance::ADDRESS as gov_address; +use namada::core::ledger::pgf::storage::keys as pgf_storage; +use namada::core::ledger::pgf::ADDRESS; +use namada::core::ledger::storage_api::governance as gov_api; +use namada::ledger::governance::utils::ProposalEvent; +use namada::ledger::pos::BondId; use namada::ledger::protocol; use namada::ledger::storage::types::encode; use namada::ledger::storage::{DBIter, StorageHasher, DB}; use namada::ledger::storage_api::{token, StorageWrite}; -use namada::proof_of_stake::read_total_stake; +use namada::proof_of_stake::parameters::PosParams; +use namada::proof_of_stake::{bond_amount, read_total_stake}; use namada::proto::{Code, Data}; use namada::types::address::Address; -use namada::types::governance::{Council, Tally, TallyResult, VotePower}; use namada::types::storage::Epoch; +use super::utils::force_read; use super::*; #[derive(Default)] @@ -40,218 +48,333 @@ where let proposal_end_epoch_key = gov_storage::get_voting_end_epoch_key(id); let proposal_type_key = gov_storage::get_proposal_type_key(id); - let funds = shell - .read_storage_key::(&proposal_funds_key) - .ok_or_else(|| { - Error::BadProposal(id, "Invalid proposal funds.".to_string()) - })?; - let proposal_end_epoch = shell - .read_storage_key::(&proposal_end_epoch_key) - .ok_or_else(|| { - Error::BadProposal( - id, - "Invalid proposal end_epoch.".to_string(), - ) - })?; - - let proposal_type = shell - .read_storage_key::(&proposal_type_key) - .ok_or_else(|| { - Error::BadProposal(id, "Invalid proposal type".to_string()) - })?; - - let votes = - get_proposal_votes(&shell.wl_storage, proposal_end_epoch, id) - .map_err(|msg| Error::BadProposal(id, msg.to_string()))?; - let params = read_pos_params(&shell.wl_storage) - .map_err(|msg| Error::BadProposal(id, msg.to_string()))?; - let total_stake = - read_total_stake(&shell.wl_storage, ¶ms, proposal_end_epoch) - .map_err(|msg| Error::BadProposal(id, msg.to_string()))?; - let total_stake = VotePower::try_from(total_stake) - .expect("Voting power exceeds NAM supply"); - let tally_result = compute_tally(votes, total_stake, &proposal_type) - .map_err(|msg| Error::BadProposal(id, msg.to_string()))? - .result; - - // Execute proposal if succesful - let transfer_address = match tally_result { - TallyResult::Passed(tally) => { - let (successful_execution, proposal_event) = match tally { - Tally::Default => execute_default_proposal(shell, id), - Tally::PGFCouncil(council) => { - execute_pgf_proposal(id, council) + let funds: token::Amount = + force_read(&shell.wl_storage, &proposal_funds_key)?; + let proposal_end_epoch: Epoch = + force_read(&shell.wl_storage, &proposal_end_epoch_key)?; + let proposal_type: ProposalType = + force_read(&shell.wl_storage, &proposal_type_key)?; + + let params = read_pos_params(&shell.wl_storage)?; + let total_voting_power = + read_total_stake(&shell.wl_storage, ¶ms, proposal_end_epoch)?; + + let tally_type = TallyType::from(proposal_type.clone()); + let votes = compute_proposal_votes( + &shell.wl_storage, + ¶ms, + id, + proposal_end_epoch, + )?; + let proposal_result = + compute_proposal_result(votes, total_voting_power, tally_type); + + let transfer_address = match proposal_result.result { + TallyResult::Passed => { + let proposal_event = match proposal_type { + ProposalType::Default(_) => { + let proposal_code_key = + gov_storage::get_proposal_code_key(id); + let proposal_code = + shell.wl_storage.read_bytes(&proposal_code_key)?; + let result = execute_default_proposal( + shell, + id, + proposal_code.clone(), + )?; + tracing::info!( + "Governance proposal (default) {} has been \ + executed ({}) and passed.", + id, + result + ); + + ProposalEvent::default_proposal_event( + id, + proposal_code.is_some(), + result, + ) + .into() } - Tally::ETHBridge => execute_eth_proposal(id), - }; + ProposalType::PGFSteward(stewards) => { + let result = execute_pgf_steward_proposal( + &mut shell.wl_storage, + stewards, + )?; + tracing::info!( + "Governance proposal (pgf stewards){} has been \ + executed and passed.", + id + ); + + ProposalEvent::pgf_steward_proposal_event(id, result) + .into() + } + ProposalType::PGFPayment(payments) => { + let native_token = + &shell.wl_storage.get_native_token()?; + let result = execute_pgf_payment_proposal( + &mut shell.wl_storage, + native_token, + payments, + )?; + tracing::info!( + "Governance proposal (pgs payments) {} has been \ + executed and passed.", + id + ); + ProposalEvent::pgf_payments_proposal_event(id, result) + .into() + } + }; response.events.push(proposal_event); - if successful_execution { - proposals_result.passed.push(id); - shell - .read_storage_key::
( - &gov_storage::get_author_key(id), - ) - .ok_or_else(|| { - Error::BadProposal( - id, - "Invalid proposal author.".to_string(), - ) - })? - } else { - proposals_result.rejected.push(id); - slash_fund_address - } + proposals_result.passed.push(id); + + let proposal_author_key = gov_storage::get_author_key(id); + shell.wl_storage.read::
(&proposal_author_key)? } TallyResult::Rejected => { - let proposal_event: Event = ProposalEvent::new( - EventType::Proposal.to_string(), - TallyResult::Rejected, - id, - false, - false, - ) - .into(); + if let ProposalType::PGFPayment(_) = proposal_type { + let two_third_nay = proposal_result.two_third_nay(); + if two_third_nay { + let pgf_stewards_key = pgf_storage::get_stewards_key(); + let proposal_author = gov_storage::get_author_key(id); + + let mut pgf_stewards = shell + .wl_storage + .read::>(&pgf_stewards_key)? + .unwrap_or_default(); + let proposal_author: Address = + force_read(&shell.wl_storage, &proposal_author)?; + + pgf_stewards.remove(&proposal_author); + shell + .wl_storage + .write(&pgf_stewards_key, pgf_stewards)?; + + tracing::info!( + "Governance proposal {} was rejected with 2/3 of \ + nay votes. Removing {} from stewards set.", + id, + proposal_author + ); + } + } + let proposal_event = + ProposalEvent::rejected_proposal_event(id).into(); response.events.push(proposal_event); proposals_result.rejected.push(id); - slash_fund_address + tracing::info!( + "Governance proposal {} has been executed and rejected.", + id + ); + + None } }; let native_token = shell.wl_storage.storage.native_token.clone(); - // transfer proposal locked funds - token::transfer( - &mut shell.wl_storage, - &native_token, - &gov_address, - &transfer_address, - funds, - ) - .expect( - "Must be able to transfer governance locked funds after proposal \ - has been tallied", - ); + if let Some(address) = transfer_address { + token::transfer( + &mut shell.wl_storage, + &native_token, + &gov_address, + &address, + funds, + )?; + } else { + token::burn( + &mut shell.wl_storage, + &native_token, + &gov_address, + funds, + )?; + } } Ok(proposals_result) } +fn compute_proposal_votes( + storage: &S, + params: &PosParams, + proposal_id: u64, + epoch: Epoch, +) -> storage_api::Result +where + S: StorageRead, +{ + let votes = gov_api::get_proposal_votes(storage, proposal_id)?; + + let mut validators_vote: HashMap = HashMap::default(); + let mut validator_voting_power: HashMap = + HashMap::default(); + let mut delegators_vote: HashMap = HashMap::default(); + let mut delegator_voting_power: HashMap< + Address, + HashMap, + > = HashMap::default(); + + for vote in votes { + if vote.is_validator() { + let validator = vote.validator.clone(); + let vote_data = vote.data.clone(); + + let validator_stake = + read_total_stake(storage, params, epoch).unwrap_or_default(); + + validators_vote.insert(validator.clone(), vote_data.into()); + validator_voting_power.insert(validator, validator_stake); + } else { + let validator = vote.validator.clone(); + let delegator = vote.delegator.clone(); + let vote_data = vote.data.clone(); + + let bond_id = BondId { + source: delegator.clone(), + validator: validator.clone(), + }; + let (_, delegator_stake) = + bond_amount(storage, &bond_id, epoch).unwrap_or_default(); + + delegators_vote.insert(delegator.clone(), vote_data.into()); + delegator_voting_power + .entry(delegator) + .or_default() + .insert(validator, delegator_stake); + } + } + + Ok(ProposalVotes { + validators_vote, + validator_voting_power, + delegators_vote, + delegator_voting_power, + }) +} + fn execute_default_proposal( shell: &mut Shell, id: u64, -) -> (bool, Event) + proposal_code: Option>, +) -> storage_api::Result where D: DB + for<'iter> DBIter<'iter> + Sync + 'static, H: StorageHasher + Sync + 'static, { - let proposal_code_key = gov_storage::get_proposal_code_key(id); - let proposal_code = shell.read_storage_key_bytes(&proposal_code_key); - match proposal_code { - Some(proposal_code) => { - let mut tx = Tx::new(TxType::Decrypted(DecryptedTx::Decrypted { - #[cfg(not(feature = "mainnet"))] - has_valid_pow: false, - })); - tx.header.chain_id = shell.chain_id.clone(); - tx.set_data(Data::new(encode(&id))); - tx.set_code(Code::new(proposal_code)); - let pending_execution_key = - gov_storage::get_proposal_execution_key(id); - shell - .wl_storage - .write(&pending_execution_key, ()) - .expect("Should be able to write to storage."); - let tx_result = protocol::dispatch_tx( - tx, - 0, /* this is used to compute the fee - * based on the code size. We dont - * need it here. */ - TxIndex::default(), - &mut BlockGasMeter::default(), - &mut shell.wl_storage, - &mut shell.vp_wasm_cache, - &mut shell.tx_wasm_cache, - ); - shell - .wl_storage - .storage - .delete(&pending_execution_key) - .expect("Should be able to delete the storage."); - match tx_result { - Ok(tx_result) if tx_result.is_accepted() => { + if let Some(code) = proposal_code { + let pending_execution_key = gov_storage::get_proposal_execution_key(id); + shell.wl_storage.write(&pending_execution_key, ())?; + + let mut tx = Tx::from_type(TxType::Decrypted(DecryptedTx::Decrypted { + #[cfg(not(feature = "mainnet"))] + has_valid_pow: false, + })); + tx.header.chain_id = shell.chain_id.clone(); + tx.set_data(Data::new(encode(&id))); + tx.set_code(Code::new(code)); + + // 0 parameter is used to compute the fee + // based on the code size. We dont + // need it here. + let tx_result = protocol::dispatch_tx( + tx, + 0, /* this is used to compute the fee + * based on the code size. We dont + * need it here. */ + TxIndex::default(), + &mut BlockGasMeter::default(), + &mut shell.wl_storage, + &mut shell.vp_wasm_cache, + &mut shell.tx_wasm_cache, + ); + shell + .wl_storage + .storage + .delete(&pending_execution_key) + .expect("Should be able to delete the storage."); + match tx_result { + Ok(tx_result) => { + if tx_result.is_accepted() { shell.wl_storage.commit_tx(); - ( - tx_result.is_accepted(), - ProposalEvent::new( - EventType::Proposal.to_string(), - TallyResult::Passed(Tally::Default), - id, - true, - tx_result.is_accepted(), - ) - .into(), - ) - } - _ => { - shell.wl_storage.drop_tx(); - ( - false, - ProposalEvent::new( - EventType::Proposal.to_string(), - TallyResult::Passed(Tally::Default), - id, - true, - false, - ) - .into(), - ) + Ok(true) + } else { + Ok(false) } } + Err(_) => { + shell.wl_storage.drop_tx(); + Ok(false) + } } - None => ( - true, - ProposalEvent::new( - EventType::Proposal.to_string(), - TallyResult::Passed(Tally::Default), - id, - false, - false, - ) - .into(), - ), + } else { + tracing::info!( + "Governance proposal {} doesn't have any associated proposal code.", + id + ); + Ok(true) } } -fn execute_pgf_proposal(id: u64, council: Council) -> (bool, Event) { - // TODO: implement when PGF is in place, update the PGF - // council in storage - ( - true, - ProposalEvent::new( - EventType::Proposal.to_string(), - TallyResult::Passed(Tally::PGFCouncil(council)), - id, - false, - false, - ) - .into(), - ) +fn execute_pgf_steward_proposal( + storage: &mut S, + stewards: HashSet>, +) -> Result +where + S: StorageRead + StorageWrite, +{ + let stewards_key = pgf_storage::get_stewards_key(); + let mut storage_stewards: BTreeSet
= + storage.read(&stewards_key)?.unwrap_or_default(); + + for action in stewards { + match action { + AddRemove::Add(steward) => storage_stewards.insert(steward), + AddRemove::Remove(steward) => storage_stewards.remove(&steward), + }; + } + + let write_result = storage.write(&stewards_key, storage_stewards); + Ok(write_result.is_ok()) } -fn execute_eth_proposal(id: u64) -> (bool, Event) { - // TODO: implement when ETH Bridge. Apply the - // modification requested by the proposal - // - ( - true, - ProposalEvent::new( - EventType::Proposal.to_string(), - TallyResult::Passed(Tally::ETHBridge), - id, - false, - false, - ) - .into(), - ) +fn execute_pgf_payment_proposal( + storage: &mut S, + token: &Address, + payments: Vec, +) -> Result +where + S: StorageRead + StorageWrite, +{ + let continous_payments_key = pgf_storage::get_payments_key(); + let mut continous_payments: BTreeSet = + storage.read(&continous_payments_key)?.unwrap_or_default(); + + for payment in payments { + match payment { + PGFAction::Continuous(action) => match action { + AddRemove::Add(target) => { + continous_payments.insert(target); + } + AddRemove::Remove(target) => { + continous_payments.remove(&target); + } + }, + PGFAction::Retro(target) => { + token::transfer( + storage, + token, + &ADDRESS, + &target.target, + target.amount, + )?; + } + } + } + + let write_result = + storage.write(&continous_payments_key, continous_payments); + Ok(write_result.is_ok()) } diff --git a/apps/src/lib/node/ledger/shell/init_chain.rs b/apps/src/lib/node/ledger/shell/init_chain.rs index ef08373789..8ad61ee45e 100644 --- a/apps/src/lib/node/ledger/shell/init_chain.rs +++ b/apps/src/lib/node/ledger/shell/init_chain.rs @@ -90,6 +90,7 @@ where implicit_vp_code_path, implicit_vp_sha256, epochs_per_year, + max_signatures_per_transaction, pos_gain_p, pos_gain_d, staked_ratio, @@ -182,6 +183,7 @@ where tx_whitelist, implicit_vp_code_hash, epochs_per_year, + max_signatures_per_transaction, pos_gain_p, pos_gain_d, staked_ratio, @@ -200,6 +202,13 @@ where .gov_params .init_storage(&mut self.wl_storage) .expect("Initializing chain parameters must not fail"); + + // Initialize pgf parameters + genesis + .pgf_params + .init_storage(&mut self.wl_storage) + .expect("Initializing chain parameters must not fail"); + // configure the Ethereum bridge if the configuration is set. if let Some(config) = genesis.ethereum_bridge_params { tracing::debug!("Initializing Ethereum bridge storage."); @@ -289,10 +298,12 @@ where .unwrap(); if let Some(pk) = public_key { - let pk_storage_key = pk_key(&address); - self.wl_storage - .write_bytes(&pk_storage_key, pk.try_to_vec().unwrap()) - .unwrap(); + storage_api::account::set_public_key_at( + &mut self.wl_storage, + &address, + &pk, + 0, + )?; } for (key, value) in storage { @@ -328,9 +339,14 @@ where ) { // Initialize genesis implicit for genesis::ImplicitAccount { public_key } in accounts { - let address: Address = (&public_key).into(); - let pk_storage_key = pk_key(&address); - self.wl_storage.write(&pk_storage_key, public_key).unwrap(); + let address: address::Address = (&public_key).into(); + storage_api::account::set_public_key_at( + &mut self.wl_storage, + &address, + &public_key, + 0, + ) + .unwrap(); } } @@ -390,10 +406,13 @@ where .write_bytes(&Key::validity_predicate(addr), vp_code_hash) .expect("Unable to write user VP"); // Validator account key - let pk_key = pk_key(addr); - self.wl_storage - .write(&pk_key, &validator.account_key) - .expect("Unable to set genesis user public key"); + storage_api::account::set_public_key_at( + &mut self.wl_storage, + addr, + &validator.account_key, + 0, + ) + .unwrap(); // Balances // Account balance (tokens not staked in PoS) diff --git a/apps/src/lib/node/ledger/shell/mod.rs b/apps/src/lib/node/ledger/shell/mod.rs index 2b7a0b7ac7..c65fbb3f99 100644 --- a/apps/src/lib/node/ledger/shell/mod.rs +++ b/apps/src/lib/node/ledger/shell/mod.rs @@ -16,6 +16,7 @@ mod stats; #[cfg(any(test, feature = "testing"))] #[allow(dead_code)] pub mod testing; +pub mod utils; mod vote_extensions; use std::collections::{BTreeSet, HashSet}; @@ -1242,13 +1243,13 @@ where } // Check balance for fee - let fee_payer = if wrapper.pk != masp_tx_key().ref_to() { - wrapper.fee_payer() + let gas_payer = if wrapper.pk != masp_tx_key().ref_to() { + wrapper.gas_payer() } else { masp() }; // check that the fee payer has sufficient balance - let balance = self.get_balance(&wrapper.fee.token, &fee_payer); + let balance = self.get_balance(&wrapper.fee.token, &gas_payer); // In testnets with a faucet, tx is allowed to skip fees if // it includes a valid PoW @@ -1287,38 +1288,6 @@ where response } - /// Lookup a validator's keypair for their established account from their - /// wallet. If the node is not validator, this function returns None - #[allow(dead_code)] - fn get_account_keypair(&self) -> Option { - let wallet_path = &self.base_dir.join(self.chain_id.as_str()); - let genesis_path = &self - .base_dir - .join(format!("{}.toml", self.chain_id.as_str())); - let mut wallet = crate::wallet::load_or_new_from_genesis( - wallet_path, - genesis::genesis_config::open_genesis_config(genesis_path).unwrap(), - ); - self.mode.get_validator_address().map(|addr| { - let sk: common::SecretKey = self - .wl_storage - .read(&pk_key(addr)) - .expect( - "A validator should have a public key associated with \ - it's established account", - ) - .expect( - "A validator should have a public key associated with \ - it's established account", - ); - let pk = sk.ref_to(); - wallet.find_key_by_pk(&pk, None).expect( - "A validator's established keypair should be stored in its \ - wallet", - ) - }) - } - #[cfg(not(feature = "mainnet"))] /// Check if the tx has a valid PoW solution. Unlike /// `apply_pow_solution_if_valid`, this won't invalidate the solution. @@ -1922,17 +1891,18 @@ mod test_utils { .expect("begin_block failed"); let keypair = gen_keypair(); // enqueue a wrapper tx - let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: Default::default(), - token: native_token, - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut wrapper = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: Default::default(), + token: native_token, + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); wrapper.header.chain_id = shell.chain_id.clone(); wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned())); wrapper.set_data(Data::new("transaction data".as_bytes().to_owned())); @@ -2118,10 +2088,11 @@ mod abciplus_mempool_tests { ext }; let tx = { - let mut tx = Tx::new(TxType::Protocol(Box::new(ProtocolTx { - pk: protocol_key.ref_to(), - tx: ProtocolTxType::BridgePoolVext, - }))); + let mut tx = + Tx::from_type(TxType::Protocol(Box::new(ProtocolTx { + pk: protocol_key.ref_to(), + tx: ProtocolTxType::BridgePoolVext, + }))); // invalid tx type, it doesn't match the // tx type declared in the header tx.set_data(Data::new(ext.try_to_vec().expect("Test falied"))); @@ -2153,7 +2124,7 @@ mod test_mempool_validate { let keypair = super::test_utils::gen_keypair(); let mut unsigned_wrapper = - Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( Fee { amount: token::Amount::from_uint(100, 0) .expect("This can't fail"), @@ -2190,7 +2161,7 @@ mod test_mempool_validate { let keypair = super::test_utils::gen_keypair(); let mut invalid_wrapper = - Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( Fee { amount: token::Amount::from_uint(100, 0) .expect("This can't fail"), @@ -2234,10 +2205,8 @@ 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 mut tx = Tx::new(shell.chain_id.clone(), None); + tx.add_code("wasm_code".as_bytes().to_owned()); let result = shell.mempool_validate( tx.to_bytes().as_ref(), @@ -2259,18 +2228,19 @@ mod test_mempool_validate { let keypair = super::test_utils::gen_keypair(); - let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: token::Amount::from_uint(100, 0) - .expect("This can't fail"), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut wrapper = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: token::Amount::from_uint(100, 0) + .expect("This can't fail"), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); wrapper.header.chain_id = shell.chain_id.clone(); wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned())); wrapper.set_data(Data::new("transaction data".as_bytes().to_owned())); @@ -2366,18 +2336,10 @@ 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 mut tx = Tx::new(wrong_chain_id.clone(), None); + tx.add_code("wasm_code".as_bytes().to_owned()) + .add_data("transaction data".as_bytes().to_owned()) + .sign_wrapper(keypair); let result = shell.mempool_validate( tx.to_bytes().as_ref(), @@ -2401,19 +2363,11 @@ 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 mut tx = + Tx::new(shell.chain_id.clone(), Some(DateTimeUtc::default())); + tx.add_code("wasm_code".as_bytes().to_owned()) + .add_data("transaction data".as_bytes().to_owned()) + .sign_wrapper(keypair); let result = shell.mempool_validate( tx.to_bytes().as_ref(), diff --git a/apps/src/lib/node/ledger/shell/prepare_proposal.rs b/apps/src/lib/node/ledger/shell/prepare_proposal.rs index e1e94be61e..4c9356f44a 100644 --- a/apps/src/lib/node/ledger/shell/prepare_proposal.rs +++ b/apps/src/lib/node/ledger/shell/prepare_proposal.rs @@ -217,7 +217,7 @@ where let mut tx = tx.clone(); match tx.decrypt(privkey).ok() { - Some(()) => { + Some(_) => { tx.update_header(TxType::Decrypted(DecryptedTx::Decrypted { #[cfg(not(feature = "mainnet"))] has_valid_pow: *has_valid_pow, @@ -543,7 +543,7 @@ mod test_prepare_proposal { #[test] fn test_prepare_proposal_rejects_non_wrapper_tx() { let (shell, _recv, _, _) = test_utils::setup(); - let mut tx = Tx::new(TxType::Decrypted(DecryptedTx::Decrypted { + let mut tx = Tx::from_type(TxType::Decrypted(DecryptedTx::Decrypted { has_valid_pow: true, })); tx.header.chain_id = shell.chain_id.clone(); @@ -562,17 +562,18 @@ mod test_prepare_proposal { let (shell, _recv, _, _) = test_utils::setup(); let keypair = gen_keypair(); // an unsigned wrapper will cause an error in processing - let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: Default::default(), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut wrapper = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: Default::default(), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); wrapper.header.chain_id = shell.chain_id.clone(); wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned())); wrapper.set_data(Data::new("transaction_data".as_bytes().to_owned())); @@ -938,17 +939,18 @@ mod test_prepare_proposal { // create a request with two new wrappers from mempool and // two wrappers from the previous block to be decrypted for i in 0..2 { - let mut tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: Default::default(), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut tx = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: Default::default(), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); tx.header.chain_id = shell.chain_id.clone(); tx.set_code(Code::new("wasm_code".as_bytes().to_owned())); tx.set_data(Data::new( @@ -1006,17 +1008,18 @@ mod test_prepare_proposal { let (mut shell, _recv, _, _) = test_utils::setup(); let keypair = crate::wallet::defaults::daewon_keypair(); - let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: 0.into(), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut wrapper = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: 0.into(), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); wrapper.header.chain_id = shell.chain_id.clone(); wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned())); wrapper.set_data(Data::new("transaction data".as_bytes().to_owned())); @@ -1057,17 +1060,18 @@ mod test_prepare_proposal { let (shell, _recv, _, _) = test_utils::setup(); let keypair = crate::wallet::defaults::daewon_keypair(); - let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: 0.into(), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut wrapper = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: 0.into(), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); wrapper.header.chain_id = shell.chain_id.clone(); wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned())); wrapper.set_data(Data::new("transaction data".as_bytes().to_owned())); @@ -1097,17 +1101,18 @@ mod test_prepare_proposal { let (mut shell, _recv, _, _) = test_utils::setup(); let keypair = crate::wallet::defaults::daewon_keypair(); - let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: Amount::zero(), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut wrapper = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: Amount::zero(), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); wrapper.header.chain_id = shell.chain_id.clone(); wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned())); wrapper.set_data(Data::new("transaction data".as_bytes().to_owned())); @@ -1149,17 +1154,18 @@ mod test_prepare_proposal { let keypair = crate::wallet::defaults::daewon_keypair(); let keypair_2 = crate::wallet::defaults::daewon_keypair(); - let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: 0.into(), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut wrapper = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: 0.into(), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); wrapper.header.chain_id = shell.chain_id.clone(); let tx_code = Code::new("wasm_code".as_bytes().to_owned()); wrapper.set_code(tx_code.clone()); @@ -1171,7 +1177,7 @@ mod test_prepare_proposal { ))); let mut new_wrapper = - Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( Fee { amount: 0.into(), token: shell.wl_storage.storage.native_token.clone(), @@ -1212,7 +1218,7 @@ mod test_prepare_proposal { let keypair = gen_keypair(); let tx_time = DateTimeUtc::now(); let mut wrapper_tx = - Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( Fee { amount: 0.into(), token: shell.wl_storage.storage.native_token.clone(), diff --git a/apps/src/lib/node/ledger/shell/process_proposal.rs b/apps/src/lib/node/ledger/shell/process_proposal.rs index ce4f71a6f5..5010a4f211 100644 --- a/apps/src/lib/node/ledger/shell/process_proposal.rs +++ b/apps/src/lib/node/ledger/shell/process_proposal.rs @@ -841,14 +841,14 @@ where // transaction key, then the fee payer is effectively // the MASP, otherwise derive // the payer from public key. - let fee_payer = if wrapper.pk != masp_tx_key().ref_to() { - wrapper.fee_payer() + let gas_payer = if wrapper.pk != masp_tx_key().ref_to() { + wrapper.gas_payer() } else { masp() }; // check that the fee payer has sufficient balance let balance = - self.get_balance(&wrapper.fee.token, &fee_payer); + self.get_balance(&wrapper.fee.token, &gas_payer); // In testnets, tx is allowed to skip fees if it // includes a valid PoW @@ -1537,20 +1537,23 @@ mod test_process_proposal { fn test_unsigned_wrapper_rejected() { let (mut shell, _recv, _, _) = test_utils::setup_at_height(3u64); let keypair = gen_keypair(); - let mut outer_tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: Default::default(), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let public_key = keypair.ref_to(); + let mut outer_tx = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: Default::default(), + token: shell.wl_storage.storage.native_token.clone(), + }, + public_key, + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); outer_tx.header.chain_id = shell.chain_id.clone(); outer_tx.set_code(Code::new("wasm_code".as_bytes().to_owned())); outer_tx.set_data(Data::new("transaction data".as_bytes().to_owned())); + let tx = outer_tx.to_bytes(); let response = { @@ -1568,12 +1571,14 @@ mod test_process_proposal { } }; + println!("{}", response.result.info); + assert_eq!(response.result.code, u32::from(ErrorCodes::InvalidSig)); assert_eq!( response.result.info, String::from( - "WrapperTx signature verification failed: Transaction doesn't \ - have any data with a signature." + "WrapperTx signature verification failed: The wrapper \ + signature is invalid." ) ); } @@ -1584,17 +1589,18 @@ mod test_process_proposal { fn test_wrapper_bad_signature_rejected() { let (mut shell, _recv, _, _) = test_utils::setup_at_height(3u64); let keypair = gen_keypair(); - let mut outer_tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: Amount::from_uint(100, 0).expect("Test failed"), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut outer_tx = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: Amount::from_uint(100, 0).expect("Test failed"), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); outer_tx.header.chain_id = shell.chain_id.clone(); outer_tx.set_code(Code::new("wasm_code".as_bytes().to_owned())); outer_tx.set_data(Data::new("transaction data".as_bytes().to_owned())); @@ -1622,8 +1628,8 @@ mod test_process_proposal { panic!("Test failed") }; let expected_error = "WrapperTx signature verification \ - failed: Transaction doesn't have any \ - data with a signature."; + failed: The wrapper signature is \ + invalid."; assert_eq!( response.result.code, u32::from(ErrorCodes::InvalidSig) @@ -1652,17 +1658,18 @@ mod test_process_proposal { ) .unwrap(); let keypair = gen_keypair(); - let mut outer_tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: Amount::from_uint(1, 0).expect("Test failed"), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut outer_tx = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: Amount::from_uint(1, 0).expect("Test failed"), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); outer_tx.header.chain_id = shell.chain_id.clone(); outer_tx.set_code(Code::new("wasm_code".as_bytes().to_owned())); outer_tx.set_data(Data::new("transaction data".as_bytes().to_owned())); @@ -1721,17 +1728,18 @@ mod test_process_proposal { ) .unwrap(); - let mut outer_tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: Amount::native_whole(1_000_100), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut outer_tx = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: Amount::native_whole(1_000_100), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); outer_tx.header.chain_id = shell.chain_id.clone(); outer_tx.set_code(Code::new("wasm_code".as_bytes().to_owned())); outer_tx.set_data(Data::new("transaction data".as_bytes().to_owned())); @@ -1774,7 +1782,7 @@ mod test_process_proposal { let mut txs = vec![]; for i in 0..3 { let mut outer_tx = - Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( Fee { amount: Amount::native_whole(i as u64), token: shell.wl_storage.storage.native_token.clone(), @@ -1852,7 +1860,7 @@ mod test_process_proposal { let (mut shell, _recv, _, _) = test_utils::setup_at_height(3u64); let keypair = gen_keypair(); - let mut tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( + let mut tx = Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( Fee { amount: Default::default(), token: shell.wl_storage.storage.native_token.clone(), @@ -1904,7 +1912,7 @@ mod test_process_proposal { let (mut shell, _recv, _, _) = test_utils::setup_at_height(3u64); let keypair = crate::wallet::defaults::daewon_keypair(); - let mut tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( + let mut tx = Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( Fee { amount: Default::default(), token: shell.wl_storage.storage.native_token.clone(), @@ -1961,7 +1969,7 @@ mod test_process_proposal { pow_solution: None, }; - let tx = Tx::new(TxType::Wrapper(Box::new(wrapper))); + let tx = Tx::from_type(TxType::Wrapper(Box::new(wrapper))); let mut decrypted = tx.clone(); decrypted.update_header(TxType::Decrypted(DecryptedTx::Undecryptable)); @@ -1989,7 +1997,7 @@ mod test_process_proposal { #[test] fn test_too_many_decrypted_txs() { let (mut shell, _recv, _, _) = test_utils::setup_at_height(3u64); - let mut tx = Tx::new(TxType::Decrypted(DecryptedTx::Decrypted { + let mut tx = Tx::from_type(TxType::Decrypted(DecryptedTx::Decrypted { #[cfg(not(feature = "mainnet"))] has_valid_pow: false, })); @@ -2023,10 +2031,12 @@ 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 mut tx = Tx::new(shell.chain_id.clone(), None); + tx.add_code("wasm_code".as_bytes().to_owned()) + .add_data("transaction data".as_bytes().to_owned()) + .sign_wrapper(keypair); let response = { let request = ProcessProposal { @@ -2062,17 +2072,18 @@ mod test_process_proposal { let keypair = crate::wallet::defaults::daewon_keypair(); - let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: Amount::zero(), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut wrapper = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: Amount::zero(), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); wrapper.header.chain_id = shell.chain_id.clone(); wrapper.set_data(Data::new("transaction data".as_bytes().to_owned())); wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned())); @@ -2136,17 +2147,18 @@ mod test_process_proposal { ) .unwrap(); - let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: Amount::zero(), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut wrapper = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: Amount::zero(), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); wrapper.header.chain_id = shell.chain_id.clone(); wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned())); wrapper.set_data(Data::new("transaction data".as_bytes().to_owned())); @@ -2193,17 +2205,18 @@ mod test_process_proposal { let keypair = crate::wallet::defaults::daewon_keypair(); - let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: Amount::zero(), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut wrapper = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: Amount::zero(), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); wrapper.header.chain_id = shell.chain_id.clone(); wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned())); wrapper.set_data(Data::new("transaction data".as_bytes().to_owned())); @@ -2282,17 +2295,18 @@ mod test_process_proposal { ) .unwrap(); - let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: Amount::zero(), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut wrapper = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: Amount::zero(), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); wrapper.header.chain_id = shell.chain_id.clone(); wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned())); wrapper.set_data(Data::new("transaction data".as_bytes().to_owned())); @@ -2351,17 +2365,18 @@ mod test_process_proposal { let (mut shell, _recv, _, _) = test_utils::setup(); let keypair = crate::wallet::defaults::daewon_keypair(); - let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: Amount::zero(), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut wrapper = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: Amount::zero(), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); let wrong_chain_id = ChainId("Wrong chain id".to_string()); wrapper.header.chain_id = wrong_chain_id.clone(); wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned())); @@ -2413,17 +2428,18 @@ mod test_process_proposal { let keypair = crate::wallet::defaults::daewon_keypair(); let wrong_chain_id = ChainId("Wrong chain id".to_string()); - let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: token::Amount::zero(), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut wrapper = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: token::Amount::zero(), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); wrapper.header.chain_id = wrong_chain_id.clone(); wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned())); wrapper @@ -2473,17 +2489,18 @@ mod test_process_proposal { let (mut shell, _recv, _, _) = test_utils::setup(); let keypair = crate::wallet::defaults::daewon_keypair(); - let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: token::Amount::zero(), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut wrapper = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: token::Amount::zero(), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); wrapper.header.chain_id = shell.chain_id.clone(); wrapper.header.expiration = Some(DateTimeUtc::default()); wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned())); @@ -2515,17 +2532,18 @@ mod test_process_proposal { let (mut shell, _recv, _, _) = test_utils::setup(); let keypair = crate::wallet::defaults::daewon_keypair(); - let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: token::Amount::zero(), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut wrapper = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: token::Amount::zero(), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); wrapper.header.chain_id = shell.chain_id.clone(); wrapper.header.expiration = Some(DateTimeUtc::default()); wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned())); @@ -2571,17 +2589,18 @@ mod test_process_proposal { fn test_include_only_protocol_txs() { let (mut shell, _recv, _, _) = test_utils::setup_at_height(1u64); let keypair = gen_keypair(); - let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: 0.into(), - token: shell.wl_storage.storage.native_token.clone(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut wrapper = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: 0.into(), + token: shell.wl_storage.storage.native_token.clone(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); wrapper.header.chain_id = shell.chain_id.clone(); wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned())); wrapper.set_data(Data::new("transaction data".as_bytes().to_owned())); diff --git a/apps/src/lib/node/ledger/shell/utils.rs b/apps/src/lib/node/ledger/shell/utils.rs new file mode 100644 index 0000000000..e55f54e8f8 --- /dev/null +++ b/apps/src/lib/node/ledger/shell/utils.rs @@ -0,0 +1,14 @@ +use borsh::BorshDeserialize; +use namada::ledger::storage_api::{self, StorageRead}; +use namada::types::storage::Key; + +pub(super) fn force_read(storage: &S, key: &Key) -> storage_api::Result +where + S: StorageRead, + T: BorshDeserialize, +{ + storage + .read::(key) + .transpose() + .expect("Storage key must be present.") +} diff --git a/apps/src/lib/wallet/defaults.rs b/apps/src/lib/wallet/defaults.rs index 81ca184f16..8ab728c96f 100644 --- a/apps/src/lib/wallet/defaults.rs +++ b/apps/src/lib/wallet/defaults.rs @@ -8,7 +8,7 @@ pub use dev::{ validator_keys, }; use namada::ledger::wallet::alias::Alias; -use namada::ledger::{eth_bridge, governance, pos}; +use namada::ledger::{eth_bridge, governance, pgf, pos}; use namada::types::address::Address; use namada::types::key::*; @@ -22,6 +22,7 @@ pub fn addresses_from_genesis(genesis: GenesisConfig) -> Vec<(Alias, Address)> { ("pos_slash_pool".into(), pos::SLASH_POOL_ADDRESS), ("governance".into(), governance::ADDRESS), ("eth_bridge".into(), eth_bridge::ADDRESS), + ("pgf".into(), pgf::ADDRESS), ]; // Genesis validators let validator_addresses = @@ -75,7 +76,7 @@ mod dev { use borsh::BorshDeserialize; use namada::ledger::wallet::alias::Alias; - use namada::ledger::{governance, pos}; + use namada::ledger::{governance, pgf, pos}; use namada::types::address::{ apfel, btc, dot, eth, kartoffel, nam, schnitzel, Address, }; @@ -146,6 +147,7 @@ mod dev { ("pos".into(), pos::ADDRESS), ("pos_slash_pool".into(), pos::SLASH_POOL_ADDRESS), ("governance".into(), governance::ADDRESS), + ("governance".into(), pgf::ADDRESS), ("validator".into(), validator_address()), ("albert".into(), albert_address()), ("bertha".into(), bertha_address()), diff --git a/core/Cargo.toml b/core/Cargo.toml index 8b58481c17..7c5addad7c 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -40,7 +40,6 @@ abciplus = [ ibc-mocks = [ "ibc/mocks", - "ibc/std", ] ethers-derive = [ @@ -73,8 +72,8 @@ ferveo = {optional = true, git = "https://github.com/anoma/ferveo", rev = "e5abd ferveo-common = {git = "https://github.com/anoma/ferveo", rev = "e5abd0acc938da90140351a65a26472eb495ce4d"} tpke = {package = "group-threshold-cryptography", optional = true, git = "https://github.com/anoma/ferveo", rev = "e5abd0acc938da90140351a65a26472eb495ce4d"} # TODO using the same version of tendermint-rs as we do here. -ibc = { git = "https://github.com/heliaxdev/cosmos-ibc-rs.git", rev = "634f4ede136d045dd6f1ff8f4984dd0006aa15f0", default-features = false, features = ["serde"], optional = true} -ibc-proto = {git = "https://github.com/heliaxdev/ibc-proto-rs.git", rev = "bb16e17a4d9260d5f20516a8eda43fa52377fad2", default-features = false, optional = true} +ibc = { git = "https://github.com/heliaxdev/cosmos-ibc-rs.git", rev = "38a827d3901e590b2935ee5b6b81b4d67c399560", features = ["serde"], optional = true} +ibc-proto = {git = "https://github.com/heliaxdev/ibc-proto-rs.git", rev = "31892ee743b2af017d5629b2af419ee20b6100c7", default-features = false, optional = true} ics23.workspace = true impl-num-traits = "0.1.2" index-set.workspace = true diff --git a/core/src/ledger/governance/cli/mod.rs b/core/src/ledger/governance/cli/mod.rs new file mode 100644 index 0000000000..45b839d1f4 --- /dev/null +++ b/core/src/ledger/governance/cli/mod.rs @@ -0,0 +1,6 @@ +/// CLi governance offline structures +pub mod offline; +/// CLi governance on chain structures +pub mod onchain; +/// CLi governance validation +mod validation; diff --git a/core/src/ledger/governance/cli/offline.rs b/core/src/ledger/governance/cli/offline.rs new file mode 100644 index 0000000000..e63ac2ff49 --- /dev/null +++ b/core/src/ledger/governance/cli/offline.rs @@ -0,0 +1,389 @@ +use std::collections::{BTreeMap, BTreeSet}; +use std::fs::{File, ReadDir}; +use std::path::PathBuf; + +use borsh::{BorshDeserialize, BorshSerialize}; +use serde::{Deserialize, Serialize}; + +use super::onchain::ProposalVote; +use super::validation::{is_valid_tally_epoch, ProposalValidation}; +use crate::proto::SignatureIndex; +use crate::types::account::AccountPublicKeysMap; +use crate::types::address::Address; +use crate::types::hash::Hash; +use crate::types::key::{common, RefTo, SigScheme}; +use crate::types::storage::Epoch; + +#[derive( + Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, +)] +/// The offline proposal structure +pub struct OfflineProposal { + /// The proposal content + pub content: BTreeMap, + /// The proposal author address + pub author: Address, + /// The epoch from which this changes are executed + pub tally_epoch: Epoch, +} + +impl OfflineProposal { + /// Validate the offline proposal + pub fn validate( + self, + current_epoch: Epoch, + ) -> Result { + is_valid_tally_epoch(self.tally_epoch, current_epoch)?; + + Ok(self) + } + + /// Hash an offline proposal + pub fn hash(&self) -> Hash { + let content_serialized = serde_json::to_vec(&self.content) + .expect("Conversion to bytes shouldn't fail."); + let author_serialized = serde_json::to_vec(&self.author) + .expect("Conversion to bytes shouldn't fail."); + let tally_epoch_serialized = serde_json::to_vec(&self.tally_epoch) + .expect("Conversion to bytes shouldn't fail."); + let proposal_serialized = &[ + content_serialized, + author_serialized, + tally_epoch_serialized, + ] + .concat(); + Hash::sha256(proposal_serialized) + } + + /// Sign an offline proposal + pub fn sign( + self, + signing_keys: Vec, + account_public_keys_map: &AccountPublicKeysMap, + ) -> OfflineSignedProposal { + let proposal_hash = self.hash(); + + let signatures_index = compute_signatures_index( + &signing_keys, + account_public_keys_map, + &proposal_hash, + ); + + OfflineSignedProposal { + proposal: self, + signatures: signatures_index, + } + } +} + +impl TryFrom<&[u8]> for OfflineProposal { + type Error = serde_json::Error; + + fn try_from(value: &[u8]) -> Result { + serde_json::from_slice(value) + } +} + +#[derive( + Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, +)] +/// The signed offline proposal structure +pub struct OfflineSignedProposal { + /// The proposal content + pub proposal: OfflineProposal, + /// The signatures over proposal data + pub signatures: BTreeSet, +} + +impl TryFrom<&[u8]> for OfflineSignedProposal { + type Error = serde_json::Error; + + fn try_from(value: &[u8]) -> Result { + serde_json::from_slice(value) + } +} + +impl OfflineSignedProposal { + /// Serialize the proposal to file. Returns the filename if successful. + pub fn serialize( + &self, + output_folder: Option, + ) -> Result { + let proposal_filename = + format!("offline_proposal_{}.json", self.proposal.hash()); + + let filepath = match output_folder { + Some(base_path) => base_path + .join(proposal_filename) + .to_str() + .unwrap() + .to_owned(), + None => proposal_filename, + }; + + let out = + File::create(&filepath).expect("Should be able to create a file."); + serde_json::to_writer_pretty(out, self)?; + + Ok(filepath) + } + + /// Check whether the signature is valid or not + fn check_signature( + &self, + account_public_keys_map: &AccountPublicKeysMap, + threshold: u8, + ) -> bool { + let proposal_hash = self.proposal.hash(); + if self.signatures.len() < threshold as usize { + return false; + } + + let valid_signatures = compute_total_valid_signatures( + &self.signatures, + account_public_keys_map, + &proposal_hash, + ); + + valid_signatures >= threshold + } + + /// Validate an offline proposal + pub fn validate( + self, + account_public_keys_map: &AccountPublicKeysMap, + threshold: u8, + ) -> Result { + let valid_signature = + self.check_signature(account_public_keys_map, threshold); + if !valid_signature { + Err(ProposalValidation::OkNoSignature) + } else { + Ok(self) + } + } +} + +#[derive( + Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, +)] +/// The offline proposal structure +pub struct OfflineVote { + /// The proposal data hash + pub proposal_hash: Hash, + /// The proposal vote + pub vote: ProposalVote, + /// The signature over proposal data + pub signatures: BTreeSet, + /// The address corresponding to the signature pk + pub address: Address, + /// The validators address to which this address delegated to + pub delegations: Vec
, +} + +impl OfflineVote { + /// Create an offline vote for a proposal + pub fn new( + proposal: &OfflineSignedProposal, + vote: ProposalVote, + address: Address, + delegations: Vec
, + ) -> Self { + let proposal_hash = proposal.proposal.hash(); + + Self { + proposal_hash, + vote, + delegations, + signatures: BTreeSet::default(), + address, + } + } + + /// Sign the offline vote + pub fn sign( + self, + keypairs: Vec, + account_public_keys_map: &AccountPublicKeysMap, + ) -> Self { + let proposal_vote_data = self + .vote + .try_to_vec() + .expect("Conversion to bytes shouldn't fail."); + let delegations_hash = self + .delegations + .try_to_vec() + .expect("Conversion to bytes shouldn't fail."); + + let vote_hash = Hash::sha256( + [ + self.proposal_hash.to_vec(), + proposal_vote_data, + delegations_hash, + ] + .concat(), + ); + + let signatures = compute_signatures_index( + &keypairs, + account_public_keys_map, + &vote_hash, + ); + + Self { signatures, ..self } + } + + /// Check if the vote is yay + pub fn is_yay(&self) -> bool { + self.vote.is_yay() + } + + /// compute the hash of a proposal + pub fn compute_hash(&self) -> Hash { + let proposal_hash_data = self + .proposal_hash + .try_to_vec() + .expect("Conversion to bytes shouldn't fail."); + let proposal_vote_data = self + .vote + .try_to_vec() + .expect("Conversion to bytes shouldn't fail."); + let delegations_hash = self + .delegations + .try_to_vec() + .expect("Conversion to bytes shouldn't fail."); + let vote_serialized = + &[proposal_hash_data, proposal_vote_data, delegations_hash] + .concat(); + + Hash::sha256(vote_serialized) + } + + /// Check whether the signature is valid or not + pub fn check_signature( + &self, + account_public_keys_map: &AccountPublicKeysMap, + threshold: u8, + ) -> bool { + if self.signatures.len() < threshold as usize { + return false; + } + let vote_data_hash = self.compute_hash(); + + let valid_signatures = compute_total_valid_signatures( + &self.signatures, + account_public_keys_map, + &vote_data_hash, + ); + + valid_signatures >= threshold + } + + /// Serialize the proposal to file. Returns the filename if successful. + pub fn serialize( + &self, + output_folder: Option, + ) -> Result { + let vote_filename = format!( + "offline_vote_{}_{}.json", + self.proposal_hash, self.address + ); + let filepath = match output_folder { + Some(base_path) => { + base_path.join(vote_filename).to_str().unwrap().to_owned() + } + None => vote_filename, + }; + let out = File::create(&filepath).unwrap(); + serde_json::to_writer_pretty(out, self)?; + + Ok(filepath) + } +} + +/// Compute the signatures index +fn compute_signatures_index( + keys: &[common::SecretKey], + account_public_keys_map: &AccountPublicKeysMap, + hashed_data: &Hash, +) -> BTreeSet { + keys.iter() + .filter_map(|signing_key| { + let public_key = signing_key.ref_to(); + let public_key_index = + account_public_keys_map.get_index_from_public_key(&public_key); + if public_key_index.is_some() { + let signature = + common::SigScheme::sign(signing_key, hashed_data); + Some(SignatureIndex::from_single_signature(signature)) + } else { + None + } + }) + .collect::>() +} + +/// Compute the total amount of signatures +fn compute_total_valid_signatures( + signatures: &BTreeSet, + account_public_keys_map: &AccountPublicKeysMap, + hashed_data: &Hash, +) -> u8 { + signatures.iter().fold(0_u8, |acc, signature_index| { + let public_key = account_public_keys_map + .get_public_key_from_index(signature_index.index); + if let Some(pk) = public_key { + let sig_check = common::SigScheme::verify_signature( + &pk, + hashed_data, + &signature_index.signature, + ); + if sig_check.is_ok() { acc + 1 } else { acc } + } else { + acc + } + }) +} + +/// Read all offline files from a folder +pub fn read_offline_files(path: ReadDir) -> Vec { + path.filter_map(|path| { + if let Ok(path) = path { + let file_type = path.file_type(); + if let Ok(file_type) = file_type { + if file_type.is_file() + && path.file_name().to_string_lossy().contains("offline_") + { + Some(path.path()) + } else { + None + } + } else { + None + } + } else { + None + } + }) + .collect::>() +} + +/// Find offline votes from a folder +pub fn find_offline_proposal(files: &[PathBuf]) -> Option { + files + .iter() + .filter(|path| path.to_string_lossy().contains("offline_proposal_")) + .cloned() + .collect::>() + .first() + .cloned() +} + +/// Find offline votes from a folder +pub fn find_offline_votes(files: &[PathBuf]) -> Vec { + files + .iter() + .filter(|path| path.to_string_lossy().contains("offline_vote_")) + .cloned() + .collect::>() +} diff --git a/core/src/ledger/governance/cli/onchain.rs b/core/src/ledger/governance/cli/onchain.rs new file mode 100644 index 0000000000..e4051353d3 --- /dev/null +++ b/core/src/ledger/governance/cli/onchain.rs @@ -0,0 +1,333 @@ +use std::collections::BTreeMap; + +use borsh::{BorshDeserialize, BorshSerialize}; +use serde::{Deserialize, Serialize}; + +use super::validation::{ + is_valid_author_balance, is_valid_content, is_valid_default_proposal_data, + is_valid_end_epoch, is_valid_grace_epoch, is_valid_pgf_funding_data, + is_valid_pgf_stewards_data, is_valid_proposal_period, is_valid_start_epoch, + ProposalValidation, +}; +use crate::ledger::governance::parameters::GovernanceParameters; +use crate::ledger::storage_api::token; +use crate::types::address::Address; +use crate::types::storage::Epoch; + +#[derive( + Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, +)] +/// The proposal structure +pub struct OnChainProposal { + /// The proposal id + pub id: Option, + /// The proposal content + pub content: BTreeMap, + /// The proposal author address + pub author: Address, + /// The epoch from which voting is allowed + pub voting_start_epoch: Epoch, + /// The epoch from which voting is stopped + pub voting_end_epoch: Epoch, + /// The epoch from which this changes are executed + pub grace_epoch: Epoch, +} + +/// Pgf default proposal +#[derive( + Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, +)] +pub struct DefaultProposal { + /// The proposal data + pub proposal: OnChainProposal, + /// The default proposal extra data + pub data: Option>, +} + +impl DefaultProposal { + /// Validate a default funding proposal + pub fn validate( + self, + governance_parameters: &GovernanceParameters, + current_epoch: Epoch, + balance: token::Amount, + ) -> Result { + is_valid_start_epoch( + self.proposal.voting_start_epoch, + current_epoch, + governance_parameters.min_proposal_voting_period, + )?; + is_valid_end_epoch( + self.proposal.voting_start_epoch, + self.proposal.voting_end_epoch, + current_epoch, + governance_parameters.min_proposal_voting_period, + governance_parameters.min_proposal_voting_period, + governance_parameters.max_proposal_period, + )?; + is_valid_grace_epoch( + self.proposal.grace_epoch, + self.proposal.voting_end_epoch, + governance_parameters.min_proposal_grace_epochs, + )?; + is_valid_proposal_period( + self.proposal.voting_start_epoch, + self.proposal.grace_epoch, + governance_parameters.max_proposal_period, + )?; + is_valid_author_balance( + balance, + governance_parameters.min_proposal_fund, + )?; + is_valid_content( + &self.proposal.content, + governance_parameters.max_proposal_content_size, + )?; + is_valid_default_proposal_data( + &self.data, + governance_parameters.max_proposal_code_size, + )?; + + Ok(self) + } +} + +impl TryFrom<&[u8]> for DefaultProposal { + type Error = serde_json::Error; + + fn try_from(value: &[u8]) -> Result { + serde_json::from_slice(value) + } +} + +/// Pgf stewards proposal +#[derive( + Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, +)] +pub struct PgfStewardProposal { + /// The proposal data + pub proposal: OnChainProposal, + /// The Pgf steward proposal extra data + pub data: Vec, +} + +impl PgfStewardProposal { + /// Validate a Pgf stewards proposal + pub fn validate( + self, + governance_parameters: &GovernanceParameters, + current_epoch: Epoch, + balance: token::Amount, + ) -> Result { + is_valid_start_epoch( + self.proposal.voting_start_epoch, + current_epoch, + governance_parameters.min_proposal_voting_period, + )?; + is_valid_end_epoch( + self.proposal.voting_start_epoch, + self.proposal.voting_end_epoch, + current_epoch, + governance_parameters.min_proposal_voting_period, + governance_parameters.min_proposal_voting_period, + governance_parameters.max_proposal_period, + )?; + is_valid_grace_epoch( + self.proposal.grace_epoch, + self.proposal.voting_end_epoch, + governance_parameters.min_proposal_grace_epochs, + )?; + is_valid_proposal_period( + self.proposal.voting_start_epoch, + self.proposal.grace_epoch, + governance_parameters.max_proposal_period, + )?; + is_valid_author_balance( + balance, + governance_parameters.min_proposal_fund, + )?; + is_valid_content( + &self.proposal.content, + governance_parameters.max_proposal_content_size, + )?; + is_valid_pgf_stewards_data(&self.data, &self.proposal.author)?; + + Ok(self) + } +} + +impl TryFrom<&[u8]> for PgfStewardProposal { + type Error = serde_json::Error; + + fn try_from(value: &[u8]) -> Result { + serde_json::from_slice(value) + } +} + +/// Pgf funding proposal +#[derive( + Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, +)] +pub struct PgfFundingProposal { + /// The proposal data + pub proposal: OnChainProposal, + /// The Pgf funding proposal extra data + pub data: PgfFunding, +} + +impl PgfFundingProposal { + /// Validate a Pgf funding proposal + pub fn validate( + self, + governance_parameters: &GovernanceParameters, + current_epoch: Epoch, + ) -> Result { + is_valid_start_epoch( + self.proposal.voting_start_epoch, + current_epoch, + governance_parameters.min_proposal_voting_period, + )?; + is_valid_end_epoch( + self.proposal.voting_start_epoch, + self.proposal.voting_end_epoch, + current_epoch, + governance_parameters.min_proposal_voting_period, + governance_parameters.min_proposal_voting_period, + governance_parameters.max_proposal_period, + )?; + is_valid_grace_epoch( + self.proposal.grace_epoch, + self.proposal.voting_end_epoch, + governance_parameters.min_proposal_grace_epochs, + )?; + is_valid_proposal_period( + self.proposal.voting_start_epoch, + self.proposal.grace_epoch, + governance_parameters.max_proposal_period, + )?; + is_valid_content( + &self.proposal.content, + governance_parameters.max_proposal_content_size, + )?; + is_valid_pgf_funding_data(&self.data)?; + + Ok(self) + } +} + +impl TryFrom<&[u8]> for PgfFundingProposal { + type Error = serde_json::Error; + + fn try_from(value: &[u8]) -> Result { + serde_json::from_slice(value) + } +} + +/// Pgf stewards +#[derive( + Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, +)] +pub struct PgfSteward { + /// Pgf action + pub action: PgfAction, + /// steward address + pub address: Address, +} + +/// Pgf action +#[derive( + Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, +)] +pub enum PgfAction { + /// Add action + Add, + /// Remove action + Remove, +} + +impl PgfAction { + /// Check if a pgf action is adding a steward + pub fn is_add(&self) -> bool { + matches!(self, PgfAction::Add) + } +} + +/// Pgf fundings +#[derive( + Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, +)] +pub struct PgfFunding { + /// Pgf continous funding + pub continous: Vec, + /// pgf retro fundings + pub retro: Vec, +} + +/// Pgf continous funding +#[derive( + Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, +)] +pub struct PgfContinous { + /// Pgf target + pub target: PgfFundingTarget, + /// Pgf action + pub action: PgfAction, +} + +/// Pgf retro funding +#[derive( + Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, +)] +pub struct PgfRetro { + /// Pgf retro target + pub target: PgfFundingTarget, +} + +/// Pgf Target +#[derive( + Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, +)] +pub struct PgfFundingTarget { + /// Target amount + pub amount: token::Amount, + /// Target address + pub address: Address, +} + +/// Rappresent an proposal vote +#[derive( + Debug, + Clone, + BorshSerialize, + BorshDeserialize, + Serialize, + Deserialize, + PartialEq, +)] +pub enum ProposalVote { + /// Rappresent an yay proposal vote + Yay, + /// Rappresent an nay proposal vote + Nay, + /// Rappresent an invalid proposal vote + Invalid, +} + +impl TryFrom for ProposalVote { + type Error = String; + + fn try_from(value: String) -> Result { + match value.trim().to_lowercase().as_str() { + "yay" => Ok(ProposalVote::Yay), + "nay" => Ok(ProposalVote::Nay), + _ => Err("invalid vote".to_string()), + } + } +} + +impl ProposalVote { + /// Check if the proposal type is yay + pub fn is_yay(&self) -> bool { + matches!(self, ProposalVote::Yay) + } +} diff --git a/core/src/ledger/governance/cli/utils.rs b/core/src/ledger/governance/cli/utils.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/src/ledger/governance/cli/validation.rs b/core/src/ledger/governance/cli/validation.rs new file mode 100644 index 0000000000..7ea5b50c0a --- /dev/null +++ b/core/src/ledger/governance/cli/validation.rs @@ -0,0 +1,259 @@ +use std::collections::BTreeMap; + +use thiserror::Error; + +use super::onchain::{PgfFunding, PgfSteward}; +use crate::types::address::Address; +use crate::types::storage::Epoch; +use crate::types::token; + +/// This enum raprresent a proposal data +#[derive(Clone, Debug, PartialEq, Error)] +pub enum ProposalValidation { + /// The proposal field are correct but there is no signature + #[error("The proposal is not signed. Can't vote on it")] + OkNoSignature, + /// The proposal start epoch is invalid + #[error( + "Invalid proposal start epoch: {0} must be greater than current epoch \ + {1} and a multiple of {2}" + )] + InvalidStartEpoch(Epoch, Epoch, u64), + /// The proposal difference between start and end epoch is invalid + #[error( + "Invalid proposal end epoch: difference between proposal start and \ + end epoch must be at least {0}, at max {1} and the end epoch must be \ + a multiple of {0}" + )] + InvalidStartEndDifference(u64, u64), + /// The proposal difference between end and grace epoch is invalid + #[error( + "Invalid proposal grace epoch: difference between proposal grace and \ + end epoch must be at least {0}, but found {1}" + )] + InvalidEndGraceDifference(u64, u64), + /// The proposal difference between end and grace epoch is invalid + #[error( + "Invalid proposal period: difference between proposal start and grace \ + epoch must be at most {1}, but found {0}" + )] + InvalidProposalPeriod(u64, u64), + /// The proposal author does not have enought balance to pay for proposal + /// fees + #[error( + "Invalid proposal minimum funds: the author address has {0} but \ + minimum is {1}" + )] + InvalidBalance(String, String), + /// The proposal content is too large + #[error( + "Invalid proposal content length: the proposal content length is {0} \ + but maximum is {1}" + )] + InvalidContentLength(u64, u64), + /// Invalid offline proposal tally epoch + #[error( + "Invalid proposal tally epoch: tally epoch ({0}) must be less than \ + current epoch ({1})" + )] + InvalidTallyEPoch(Epoch, Epoch), + /// The proposal wasm code is not valid + #[error( + "Invalid proposal extra data: file doesn't exist or content size \ + ({0}) is to big (max {1})" + )] + InvalidDefaultProposalExtraData(u64, u64), + /// The pgf stewards data is not valid + #[error("Invalid proposal extra data: cannot be empty.")] + InvalidPgfStewardsExtraData, + /// The pgf funding data is not valid + #[error("invalid proposal extra data: cannot be empty.")] + InvalidPgfFundingExtraData, +} + +pub fn is_valid_author_balance( + author_balance: token::Amount, + min_proposal_fund: token::Amount, +) -> Result<(), ProposalValidation> { + if author_balance.can_spend(&min_proposal_fund) { + Ok(()) + } else { + Err(ProposalValidation::InvalidBalance( + author_balance.to_string_native(), + min_proposal_fund.to_string_native(), + )) + } +} + +pub fn is_valid_start_epoch( + proposal_start_epoch: Epoch, + current_epoch: Epoch, + proposal_epoch_multiplier: u64, +) -> Result<(), ProposalValidation> { + let start_epoch_greater_than_current = proposal_start_epoch > current_epoch; + let start_epoch_is_multipler = + proposal_start_epoch.0 % proposal_epoch_multiplier == 0; + + if start_epoch_greater_than_current && start_epoch_is_multipler { + Ok(()) + } else { + Err(ProposalValidation::InvalidStartEpoch( + proposal_start_epoch, + current_epoch, + proposal_epoch_multiplier, + )) + } +} + +pub fn is_valid_end_epoch( + proposal_start_epoch: Epoch, + proposal_end_epoch: Epoch, + _current_epoch: Epoch, + proposal_epoch_multiplier: u64, + min_proposal_voting_period: u64, + max_proposal_period: u64, +) -> Result<(), ProposalValidation> { + let voting_period = proposal_end_epoch.0 - proposal_start_epoch.0; + let end_epoch_is_multipler = + proposal_end_epoch % proposal_epoch_multiplier == 0; + let is_valid_voting_period = voting_period > 0 + && voting_period >= min_proposal_voting_period + && min_proposal_voting_period <= max_proposal_period; + + if end_epoch_is_multipler && is_valid_voting_period { + Ok(()) + } else { + Err(ProposalValidation::InvalidStartEndDifference( + min_proposal_voting_period, + max_proposal_period, + )) + } +} + +pub fn is_valid_grace_epoch( + proposal_grace_epoch: Epoch, + proposal_end_epoch: Epoch, + min_proposal_grace_epoch: u64, +) -> Result<(), ProposalValidation> { + let grace_period = proposal_grace_epoch.0 - proposal_end_epoch.0; + + if grace_period > 0 && grace_period >= min_proposal_grace_epoch { + Ok(()) + } else { + Err(ProposalValidation::InvalidEndGraceDifference( + grace_period, + min_proposal_grace_epoch, + )) + } +} + +pub fn is_valid_proposal_period( + proposal_start_epoch: Epoch, + proposal_grace_epoch: Epoch, + max_proposal_period: u64, +) -> Result<(), ProposalValidation> { + let proposal_period = proposal_grace_epoch.0 - proposal_start_epoch.0; + + if proposal_period > 0 && proposal_period <= max_proposal_period { + Ok(()) + } else { + Err(ProposalValidation::InvalidProposalPeriod( + proposal_period, + max_proposal_period, + )) + } +} + +pub fn is_valid_content( + proposal_content: &BTreeMap, + max_content_length: u64, +) -> Result<(), ProposalValidation> { + let proposal_content_keys_length: u64 = + proposal_content.keys().map(|key| key.len() as u64).sum(); + let proposal_content_values_length: u64 = proposal_content + .values() + .map(|value| value.len() as u64) + .sum(); + let proposal_content_length = + proposal_content_values_length + proposal_content_keys_length; + + if proposal_content_length <= max_content_length { + Ok(()) + } else { + Err(ProposalValidation::InvalidContentLength( + proposal_content_length, + max_content_length, + )) + } +} + +pub fn is_valid_tally_epoch( + tally_epoch: Epoch, + current_epoch: Epoch, +) -> Result<(), ProposalValidation> { + if tally_epoch <= current_epoch { + Ok(()) + } else { + Err(ProposalValidation::InvalidTallyEPoch( + tally_epoch, + current_epoch, + )) + } +} + +pub fn is_valid_default_proposal_data( + data: &Option>, + max_extra_data_size: u64, +) -> Result<(), ProposalValidation> { + match data { + Some(content) => { + let extra_data_length = content.len() as u64; + if extra_data_length <= max_extra_data_size { + Ok(()) + } else { + Err(ProposalValidation::InvalidDefaultProposalExtraData( + extra_data_length, + max_extra_data_size, + )) + } + } + None => Ok(()), + } +} + +pub fn is_valid_pgf_stewards_data( + data: &Vec, + author: &Address, +) -> Result<(), ProposalValidation> { + if !data.is_empty() { + let total_added_stewards = data + .iter() + .filter(|steward| steward.action.is_add()) + .cloned() + .collect::>(); + if total_added_stewards.len() > 1 { + Err(ProposalValidation::InvalidPgfStewardsExtraData) + } else if total_added_stewards.is_empty() { + Ok(()) + } else { + let steward_address = &total_added_stewards.get(0).unwrap().address; + if steward_address.eq(author) { + return Ok(()); + } else { + return Err(ProposalValidation::InvalidPgfStewardsExtraData); + } + } + } else { + Err(ProposalValidation::InvalidPgfStewardsExtraData) + } +} + +pub fn is_valid_pgf_funding_data( + data: &PgfFunding, +) -> Result<(), ProposalValidation> { + if !data.continous.is_empty() || !data.retro.is_empty() { + Ok(()) + } else { + Err(ProposalValidation::InvalidPgfFundingExtraData) + } +} diff --git a/core/src/ledger/governance/mod.rs b/core/src/ledger/governance/mod.rs index ae488383bf..00fcb3a990 100644 --- a/core/src/ledger/governance/mod.rs +++ b/core/src/ledger/governance/mod.rs @@ -2,10 +2,14 @@ use crate::types::address::{self, Address}; +/// governance CLI structures +pub mod cli; /// governance parameters pub mod parameters; /// governance storage pub mod storage; +/// Governance utility functions/structs +pub mod utils; /// The governance internal address pub const ADDRESS: Address = address::GOV; diff --git a/core/src/ledger/governance/parameters.rs b/core/src/ledger/governance/parameters.rs index 2d247bc24f..ebb28372af 100644 --- a/core/src/ledger/governance/parameters.rs +++ b/core/src/ledger/governance/parameters.rs @@ -2,9 +2,9 @@ use std::fmt::Display; use borsh::{BorshDeserialize, BorshSerialize}; -use super::storage as gov_storage; +use super::storage::keys as goverance_storage; use crate::ledger::storage_api::{self, StorageRead, StorageWrite}; -use crate::types::token::Amount; +use crate::types::token; #[derive( Clone, @@ -18,13 +18,13 @@ use crate::types::token::Amount; BorshDeserialize, )] /// Governance parameter structure -pub struct GovParams { +pub struct GovernanceParameters { /// Minimum amount of locked funds - pub min_proposal_fund: u64, + pub min_proposal_fund: token::Amount, /// Maximum kibibyte length for proposal code pub max_proposal_code_size: u64, /// Minimum proposal voting period in epochs - pub min_proposal_period: u64, + pub min_proposal_voting_period: u64, /// Maximum proposal voting period in epochs pub max_proposal_period: u64, /// Maximum number of characters for proposal content @@ -33,16 +33,16 @@ pub struct GovParams { pub min_proposal_grace_epochs: u64, } -impl Display for GovParams { +impl Display for GovernanceParameters { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "Min. proposal fund: {}\nMax. proposal code size: {}\nMin. \ proposal period: {}\nMax. proposal period: {}\nMax. proposal \ content size: {}\nMin. proposal grace epochs: {}", - self.min_proposal_fund, + self.min_proposal_fund.to_string_native(), self.max_proposal_code_size, - self.min_proposal_period, + self.min_proposal_voting_period, self.max_proposal_period, self.max_proposal_content_size, self.min_proposal_grace_epochs @@ -50,12 +50,12 @@ impl Display for GovParams { } } -impl Default for GovParams { +impl Default for GovernanceParameters { fn default() -> Self { Self { - min_proposal_fund: 500, + min_proposal_fund: token::Amount::native_whole(500), max_proposal_code_size: 300_000, - min_proposal_period: 3, + min_proposal_voting_period: 3, max_proposal_period: 27, max_proposal_content_size: 10_000, min_proposal_grace_epochs: 6, @@ -63,7 +63,7 @@ impl Default for GovParams { } } -impl GovParams { +impl GovernanceParameters { /// Initialize governance parameters into storage pub fn init_storage(&self, storage: &mut S) -> storage_api::Result<()> where @@ -72,39 +72,42 @@ impl GovParams { let Self { min_proposal_fund, max_proposal_code_size, - min_proposal_period, + min_proposal_voting_period, max_proposal_period, max_proposal_content_size, min_proposal_grace_epochs, } = self; - let min_proposal_fund_key = gov_storage::get_min_proposal_fund_key(); - let amount = Amount::native_whole(*min_proposal_fund); - storage.write(&min_proposal_fund_key, amount)?; + let min_proposal_fund_key = + goverance_storage::get_min_proposal_fund_key(); + storage.write(&min_proposal_fund_key, min_proposal_fund)?; let max_proposal_code_size_key = - gov_storage::get_max_proposal_code_size_key(); + goverance_storage::get_max_proposal_code_size_key(); storage.write(&max_proposal_code_size_key, max_proposal_code_size)?; - let min_proposal_period_key = - gov_storage::get_min_proposal_period_key(); - storage.write(&min_proposal_period_key, min_proposal_period)?; + let min_proposal_voting_period_key = + goverance_storage::get_min_proposal_voting_period_key(); + storage.write( + &min_proposal_voting_period_key, + min_proposal_voting_period, + )?; let max_proposal_period_key = - gov_storage::get_max_proposal_period_key(); + goverance_storage::get_max_proposal_period_key(); storage.write(&max_proposal_period_key, max_proposal_period)?; let max_proposal_content_size_key = - gov_storage::get_max_proposal_content_key(); + goverance_storage::get_max_proposal_content_key(); storage .write(&max_proposal_content_size_key, max_proposal_content_size)?; let min_proposal_grace_epoch_key = - gov_storage::get_min_proposal_grace_epoch_key(); + goverance_storage::get_min_proposal_grace_epoch_key(); storage .write(&min_proposal_grace_epoch_key, min_proposal_grace_epochs)?; - let counter_key = gov_storage::get_counter_key(); + let counter_key = goverance_storage::get_counter_key(); storage.write(&counter_key, u64::MIN) } } diff --git a/core/src/ledger/governance/storage.rs b/core/src/ledger/governance/storage/keys.rs similarity index 78% rename from core/src/ledger/governance/storage.rs rename to core/src/ledger/governance/storage/keys.rs index e00c4be678..a975b6541f 100644 --- a/core/src/ledger/governance/storage.rs +++ b/core/src/ledger/governance/storage/keys.rs @@ -1,27 +1,32 @@ +use namada_macros::StorageKeys; + use crate::ledger::governance::ADDRESS; use crate::types::address::Address; use crate::types::storage::{DbKeySeg, Key, KeySeg}; -const PROPOSAL_PREFIX: &str = "proposal"; -const PROPOSAL_VOTE: &str = "vote"; -const PROPOSAL_AUTHOR: &str = "author"; -const PROPOSAL_TYPE: &str = "type"; -const PROPOSAL_CONTENT: &str = "content"; -const PROPOSAL_START_EPOCH: &str = "start_epoch"; -const PROPOSAL_END_EPOCH: &str = "end_epoch"; -const PROPOSAL_GRACE_EPOCH: &str = "grace_epoch"; -const PROPOSAL_FUNDS: &str = "funds"; -const PROPOSAL_CODE: &str = "proposal_code"; -const PROPOSAL_COMMITTING_EPOCH: &str = "epoch"; - -const MIN_PROPOSAL_FUND_KEY: &str = "min_fund"; -const MAX_PROPOSAL_CODE_SIZE_KEY: &str = "max_code_size"; -const MIN_PROPOSAL_PERIOD_KEY: &str = "min_period"; -const MAX_PROPOSAL_PERIOD_KEY: &str = "max_period"; -const MAX_PROPOSAL_CONTENT_SIZE_KEY: &str = "max_content"; -const MIN_GRACE_EPOCH_KEY: &str = "min_grace_epoch"; -const COUNTER_KEY: &str = "counter"; -const PENDING_PROPOSAL: &str = "pending"; +/// Storage keys for governance internal address. +#[derive(StorageKeys)] +struct Keys { + proposal: &'static str, + vote: &'static str, + author: &'static str, + proposal_type: &'static str, + content: &'static str, + start_epoch: &'static str, + end_epoch: &'static str, + grace_epoch: &'static str, + funds: &'static str, + proposal_code: &'static str, + committing_epoch: &'static str, + min_fund: &'static str, + max_code_size: &'static str, + min_period: &'static str, + max_period: &'static str, + max_content: &'static str, + min_grace_epoch: &'static str, + counter: &'static str, + pending: &'static str, +} /// Check if key is inside governance address space pub fn is_governance_key(key: &Key) -> bool { @@ -39,8 +44,8 @@ pub fn is_vote_key(key: &Key) -> bool { DbKeySeg::AddressSeg(_validator_address), DbKeySeg::AddressSeg(_address), ] if addr == &ADDRESS - && prefix == PROPOSAL_PREFIX - && vote == PROPOSAL_VOTE => + && prefix == Keys::VALUES.proposal + && vote == Keys::VALUES.vote => { id.parse::().is_ok() } @@ -57,8 +62,8 @@ pub fn is_author_key(key: &Key) -> bool { DbKeySeg::StringSeg(id), DbKeySeg::StringSeg(author), ] if addr == &ADDRESS - && prefix == PROPOSAL_PREFIX - && author == PROPOSAL_AUTHOR => + && prefix == Keys::VALUES.proposal + && author == Keys::VALUES.author => { id.parse::().is_ok() } @@ -75,8 +80,8 @@ pub fn is_proposal_code_key(key: &Key) -> bool { DbKeySeg::StringSeg(id), DbKeySeg::StringSeg(proposal_code), ] if addr == &ADDRESS - && prefix == PROPOSAL_PREFIX - && proposal_code == PROPOSAL_CODE => + && prefix == Keys::VALUES.proposal + && proposal_code == Keys::VALUES.proposal_code => { id.parse::().is_ok() } @@ -93,8 +98,8 @@ pub fn is_grace_epoch_key(key: &Key) -> bool { DbKeySeg::StringSeg(id), DbKeySeg::StringSeg(grace_epoch), ] if addr == &ADDRESS - && prefix == PROPOSAL_PREFIX - && grace_epoch == PROPOSAL_GRACE_EPOCH => + && prefix == Keys::VALUES.proposal + && grace_epoch == Keys::VALUES.grace_epoch => { id.parse::().is_ok() } @@ -111,8 +116,8 @@ pub fn is_content_key(key: &Key) -> bool { DbKeySeg::StringSeg(id), DbKeySeg::StringSeg(content), ] if addr == &ADDRESS - && prefix == PROPOSAL_PREFIX - && content == PROPOSAL_CONTENT => + && prefix == Keys::VALUES.proposal + && content == Keys::VALUES.content => { id.parse::().is_ok() } @@ -129,8 +134,8 @@ pub fn is_balance_key(key: &Key) -> bool { DbKeySeg::StringSeg(id), DbKeySeg::StringSeg(funds), ] if addr == &ADDRESS - && prefix == PROPOSAL_PREFIX - && funds == PROPOSAL_FUNDS => + && prefix == Keys::VALUES.proposal + && funds == Keys::VALUES.funds => { id.parse::().is_ok() } @@ -147,8 +152,8 @@ pub fn is_start_epoch_key(key: &Key) -> bool { DbKeySeg::StringSeg(id), DbKeySeg::StringSeg(start_epoch), ] if addr == &ADDRESS - && prefix == PROPOSAL_PREFIX - && start_epoch == PROPOSAL_START_EPOCH => + && prefix == Keys::VALUES.proposal + && start_epoch == Keys::VALUES.start_epoch => { id.parse::().is_ok() } @@ -165,8 +170,8 @@ pub fn is_end_epoch_key(key: &Key) -> bool { DbKeySeg::StringSeg(id), DbKeySeg::StringSeg(end_epoch), ] if addr == &ADDRESS - && prefix == PROPOSAL_PREFIX - && end_epoch == PROPOSAL_END_EPOCH => + && prefix == Keys::VALUES.proposal + && end_epoch == Keys::VALUES.end_epoch => { id.parse::().is_ok() } @@ -183,8 +188,8 @@ pub fn is_proposal_type_key(key: &Key) -> bool { DbKeySeg::StringSeg(id), DbKeySeg::StringSeg(proposal_type), ] if addr == &ADDRESS - && prefix == PROPOSAL_PREFIX - && proposal_type == PROPOSAL_TYPE => + && prefix == Keys::VALUES.proposal + && proposal_type == Keys::VALUES.proposal_type => { id.parse::().is_ok() } @@ -194,7 +199,7 @@ pub fn is_proposal_type_key(key: &Key) -> bool { /// Check if key is counter key pub fn is_counter_key(key: &Key) -> bool { - matches!(&key.segments[..], [DbKeySeg::AddressSeg(addr), DbKeySeg::StringSeg(counter)] if addr == &ADDRESS && counter == COUNTER_KEY) + matches!(&key.segments[..], [DbKeySeg::AddressSeg(addr), DbKeySeg::StringSeg(counter)] if addr == &ADDRESS && counter == Keys::VALUES.counter) } /// Check if key is a proposal fund parameter key @@ -202,7 +207,7 @@ pub fn is_min_proposal_fund_key(key: &Key) -> bool { matches!(&key.segments[..], [ DbKeySeg::AddressSeg(addr), DbKeySeg::StringSeg(min_funds_param), - ] if addr == &ADDRESS && min_funds_param == MIN_PROPOSAL_FUND_KEY) + ] if addr == &ADDRESS && min_funds_param == Keys::VALUES.min_fund) } /// Check if key is a proposal max content parameter key @@ -211,7 +216,7 @@ pub fn is_max_content_size_key(key: &Key) -> bool { DbKeySeg::AddressSeg(addr), DbKeySeg::StringSeg(max_content_size_param), ] if addr == &ADDRESS - && max_content_size_param == MAX_PROPOSAL_CONTENT_SIZE_KEY) + && max_content_size_param == Keys::VALUES.max_content) } /// Check if key is a max proposal size key @@ -220,16 +225,16 @@ pub fn is_max_proposal_code_size_key(key: &Key) -> bool { DbKeySeg::AddressSeg(addr), DbKeySeg::StringSeg(max_content_size_param), ] if addr == &ADDRESS - && max_content_size_param == MAX_PROPOSAL_CONTENT_SIZE_KEY) + && max_content_size_param == Keys::VALUES.max_code_size) } /// Check if key is a min proposal period param key -pub fn is_min_proposal_period_key(key: &Key) -> bool { +pub fn is_min_proposal_voting_period_key(key: &Key) -> bool { matches!(&key.segments[..], [ DbKeySeg::AddressSeg(addr), - DbKeySeg::StringSeg(min_proposal_period_param), + DbKeySeg::StringSeg(min_proposal_voting_period_param), ] if addr == &ADDRESS - && min_proposal_period_param == MIN_PROPOSAL_PERIOD_KEY) + && min_proposal_voting_period_param == Keys::VALUES.min_period) } /// Check if key is a max proposal period param key @@ -238,7 +243,7 @@ pub fn is_max_proposal_period_key(key: &Key) -> bool { DbKeySeg::AddressSeg(addr), DbKeySeg::StringSeg(max_proposal_period_param), ] if addr == &ADDRESS - && max_proposal_period_param == MAX_PROPOSAL_PERIOD_KEY) + && max_proposal_period_param == Keys::VALUES.max_period) } /// Check if key is a min grace epoch key @@ -250,8 +255,8 @@ pub fn is_commit_proposal_key(key: &Key) -> bool { DbKeySeg::StringSeg(_epoch), DbKeySeg::StringSeg(_id), ] if addr == &ADDRESS - && prefix == PROPOSAL_PREFIX - && epoch_prefix == PROPOSAL_COMMITTING_EPOCH + && prefix == Keys::VALUES.proposal + && epoch_prefix == Keys::VALUES.committing_epoch ) } @@ -261,7 +266,7 @@ pub fn is_min_grace_epoch_key(key: &Key) -> bool { DbKeySeg::AddressSeg(addr), DbKeySeg::StringSeg(min_grace_epoch_param), ] if addr == &ADDRESS - && min_grace_epoch_param == MIN_GRACE_EPOCH_KEY) + && min_grace_epoch_param == Keys::VALUES.min_grace_epoch) } /// Check if key is parameter key @@ -269,7 +274,7 @@ pub fn is_parameter_key(key: &Key) -> bool { is_min_proposal_fund_key(key) || is_max_content_size_key(key) || is_max_proposal_code_size_key(key) - || is_min_proposal_period_key(key) + || is_min_proposal_voting_period_key(key) || is_max_proposal_period_key(key) || is_min_grace_epoch_key(key) } @@ -282,56 +287,56 @@ pub fn is_start_or_end_epoch_key(key: &Key) -> bool { /// Get governance prefix key pub fn proposal_prefix() -> Key { Key::from(ADDRESS.to_db_key()) - .push(&PROPOSAL_PREFIX.to_owned()) + .push(&Keys::VALUES.proposal.to_owned()) .expect("Cannot obtain a storage key") } /// Get key for the minimum proposal fund pub fn get_min_proposal_fund_key() -> Key { Key::from(ADDRESS.to_db_key()) - .push(&MIN_PROPOSAL_FUND_KEY.to_owned()) + .push(&Keys::VALUES.min_fund.to_owned()) .expect("Cannot obtain a storage key") } /// Get maximum proposal code size key pub fn get_max_proposal_code_size_key() -> Key { Key::from(ADDRESS.to_db_key()) - .push(&MAX_PROPOSAL_CODE_SIZE_KEY.to_owned()) + .push(&Keys::VALUES.max_code_size.to_owned()) .expect("Cannot obtain a storage key") } /// Get minimum proposal period key -pub fn get_min_proposal_period_key() -> Key { +pub fn get_min_proposal_voting_period_key() -> Key { Key::from(ADDRESS.to_db_key()) - .push(&MIN_PROPOSAL_PERIOD_KEY.to_owned()) + .push(&Keys::VALUES.min_period.to_owned()) .expect("Cannot obtain a storage key") } /// Get maximum proposal period key pub fn get_max_proposal_period_key() -> Key { Key::from(ADDRESS.to_db_key()) - .push(&MAX_PROPOSAL_PERIOD_KEY.to_owned()) + .push(&Keys::VALUES.max_period.to_owned()) .expect("Cannot obtain a storage key") } /// Get maximum proposal content key pub fn get_max_proposal_content_key() -> Key { Key::from(ADDRESS.to_db_key()) - .push(&MAX_PROPOSAL_CONTENT_SIZE_KEY.to_owned()) + .push(&Keys::VALUES.max_content.to_owned()) .expect("Cannot obtain a storage key") } /// Get min grace epoch proposal key pub fn get_min_proposal_grace_epoch_key() -> Key { Key::from(ADDRESS.to_db_key()) - .push(&MIN_GRACE_EPOCH_KEY.to_owned()) + .push(&Keys::VALUES.min_grace_epoch.to_owned()) .expect("Cannot obtain a storage key") } /// Get key of proposal ids counter pub fn get_counter_key() -> Key { Key::from(ADDRESS.to_db_key()) - .push(&COUNTER_KEY.to_owned()) + .push(&Keys::VALUES.counter.to_owned()) .expect("Cannot obtain a storage key") } @@ -340,7 +345,7 @@ pub fn get_content_key(id: u64) -> Key { proposal_prefix() .push(&id.to_string()) .expect("Cannot obtain a storage key") - .push(&PROPOSAL_CONTENT.to_owned()) + .push(&Keys::VALUES.content.to_owned()) .expect("Cannot obtain a storage key") } @@ -349,7 +354,7 @@ pub fn get_author_key(id: u64) -> Key { proposal_prefix() .push(&id.to_string()) .expect("Cannot obtain a storage key") - .push(&PROPOSAL_AUTHOR.to_owned()) + .push(&Keys::VALUES.author.to_owned()) .expect("Cannot obtain a storage key") } @@ -358,7 +363,7 @@ pub fn get_proposal_type_key(id: u64) -> Key { proposal_prefix() .push(&id.to_string()) .expect("Cannot obtain a storage key") - .push(&PROPOSAL_TYPE.to_owned()) + .push(&Keys::VALUES.proposal_type.to_owned()) .expect("Cannot obtain a storage key") } @@ -367,7 +372,7 @@ pub fn get_voting_start_epoch_key(id: u64) -> Key { proposal_prefix() .push(&id.to_string()) .expect("Cannot obtain a storage key") - .push(&PROPOSAL_START_EPOCH.to_owned()) + .push(&Keys::VALUES.start_epoch.to_owned()) .expect("Cannot obtain a storage key") } @@ -376,7 +381,7 @@ pub fn get_voting_end_epoch_key(id: u64) -> Key { proposal_prefix() .push(&id.to_string()) .expect("Cannot obtain a storage key") - .push(&PROPOSAL_END_EPOCH.to_owned()) + .push(&Keys::VALUES.end_epoch.to_owned()) .expect("Cannot obtain a storage key") } @@ -385,7 +390,7 @@ pub fn get_funds_key(id: u64) -> Key { proposal_prefix() .push(&id.to_string()) .expect("Cannot obtain a storage key") - .push(&PROPOSAL_FUNDS.to_owned()) + .push(&Keys::VALUES.funds.to_owned()) .expect("Cannot obtain a storage key") } @@ -394,14 +399,14 @@ pub fn get_grace_epoch_key(id: u64) -> Key { proposal_prefix() .push(&id.to_string()) .expect("Cannot obtain a storage key") - .push(&PROPOSAL_GRACE_EPOCH.to_owned()) + .push(&Keys::VALUES.grace_epoch.to_owned()) .expect("Cannot obtain a storage key") } /// Get the proposal committing key prefix pub fn get_commiting_proposals_prefix(epoch: u64) -> Key { proposal_prefix() - .push(&PROPOSAL_COMMITTING_EPOCH.to_owned()) + .push(&Keys::VALUES.committing_epoch.to_owned()) .expect("Cannot obtain a storage key") .push(&epoch.to_string()) .expect("Cannot obtain a storage key") @@ -412,7 +417,7 @@ pub fn get_proposal_code_key(id: u64) -> Key { proposal_prefix() .push(&id.to_string()) .expect("Cannot obtain a storage key") - .push(&PROPOSAL_CODE.to_owned()) + .push(&Keys::VALUES.proposal_code.to_owned()) .expect("Cannot obtain a storage key") } @@ -428,7 +433,7 @@ pub fn get_proposal_vote_prefix_key(id: u64) -> Key { proposal_prefix() .push(&id.to_string()) .expect("Cannot obtain a storage key") - .push(&PROPOSAL_VOTE.to_owned()) + .push(&Keys::VALUES.vote.to_owned()) .expect("Cannot obtain a storage key") } @@ -448,7 +453,7 @@ pub fn get_vote_proposal_key( /// Get the proposal execution key pub fn get_proposal_execution_key(id: u64) -> Key { Key::from(ADDRESS.to_db_key()) - .push(&PENDING_PROPOSAL.to_owned()) + .push(&Keys::VALUES.pending.to_owned()) .expect("Cannot obtain a storage key") .push(&id.to_string()) .expect("Cannot obtain a storage key") diff --git a/core/src/ledger/governance/storage/mod.rs b/core/src/ledger/governance/storage/mod.rs new file mode 100644 index 0000000000..e2de8e6ab8 --- /dev/null +++ b/core/src/ledger/governance/storage/mod.rs @@ -0,0 +1,6 @@ +/// Governance proposal keys +pub mod keys; +/// Proposal structures +pub mod proposal; +/// Vote structures +pub mod vote; diff --git a/core/src/ledger/governance/storage/proposal.rs b/core/src/ledger/governance/storage/proposal.rs new file mode 100644 index 0000000000..b5ac1284c4 --- /dev/null +++ b/core/src/ledger/governance/storage/proposal.rs @@ -0,0 +1,270 @@ +use std::collections::{BTreeMap, HashSet}; +use std::fmt::Display; + +use borsh::{BorshDeserialize, BorshSerialize}; +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +use crate::ledger::governance::cli::onchain::{ + PgfAction, PgfContinous, PgfRetro, PgfSteward, +}; +use crate::ledger::governance::utils::{ProposalStatus, TallyType}; +use crate::ledger::storage_api::token::Amount; +use crate::types::address::Address; +use crate::types::hash::Hash; +use crate::types::storage::Epoch; + +#[allow(missing_docs)] +#[derive(Debug, Error)] +pub enum ProposalTypeError { + #[error("Invalid proposal type.")] + InvalidProposalType, +} + +/// An add or remove action for PGF +#[derive( + Debug, + Clone, + Hash, + PartialEq, + Eq, + PartialOrd, + BorshSerialize, + BorshDeserialize, + Serialize, + Deserialize, +)] +pub enum AddRemove { + /// Add + Add(T), + /// Remove + Remove(T), +} + +/// The target of a PGF payment +#[derive( + Debug, + Clone, + PartialEq, + BorshSerialize, + BorshDeserialize, + Serialize, + Deserialize, + Ord, + Eq, + PartialOrd, +)] +pub struct PGFTarget { + /// The target address + pub target: Address, + /// The amount of token to fund the target address + pub amount: Amount, +} + +/// The actions that a PGF Steward can propose to execute +#[derive( + Debug, + Clone, + PartialEq, + BorshSerialize, + BorshDeserialize, + Serialize, + Deserialize, +)] +pub enum PGFAction { + /// A continuous payment + Continuous(AddRemove), + /// A retro payment + Retro(PGFTarget), +} + +/// The type of a Proposal +#[derive( + Debug, + Clone, + PartialEq, + BorshSerialize, + BorshDeserialize, + Serialize, + Deserialize, +)] +pub enum ProposalType { + /// Default governance proposal with the optional wasm code + Default(Option), + /// PGF stewards proposal + PGFSteward(HashSet>), + /// PGF funding proposal + PGFPayment(Vec), +} + +impl ProposalType { + /// Check if the proposal type is default + pub fn is_default(&self) -> bool { + matches!(self, ProposalType::Default(_)) + } +} + +impl Display for ProposalType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ProposalType::Default(_) => write!(f, "Default"), + ProposalType::PGFSteward(_) => write!(f, "Pgf steward"), + ProposalType::PGFPayment(_) => write!(f, "Pgf funding"), + } + } +} + +impl TryFrom for AddRemove
{ + type Error = ProposalTypeError; + + fn try_from(value: PgfSteward) -> Result { + match value.action { + PgfAction::Add => Ok(AddRemove::Add(value.address)), + PgfAction::Remove => Ok(AddRemove::Remove(value.address)), + } + } +} + +impl TryFrom for PGFAction { + type Error = ProposalTypeError; + + fn try_from(value: PgfContinous) -> Result { + match value.action { + PgfAction::Add => { + Ok(PGFAction::Continuous(AddRemove::Add(PGFTarget { + target: value.target.address, + amount: value.target.amount, + }))) + } + PgfAction::Remove => { + Ok(PGFAction::Continuous(AddRemove::Remove(PGFTarget { + target: value.target.address, + amount: value.target.amount, + }))) + } + } + } +} + +impl TryFrom for PGFAction { + type Error = ProposalTypeError; + + fn try_from(value: PgfRetro) -> Result { + Ok(PGFAction::Retro(PGFTarget { + target: value.target.address, + amount: value.target.amount, + })) + } +} + +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] +/// Proposal rappresentation when fetched from the storage +pub struct StorageProposal { + /// The proposal id + pub id: u64, + /// The proposal content + pub content: BTreeMap, + /// The proposal author address + pub author: Address, + /// The proposal type + pub r#type: ProposalType, + /// The epoch from which voting is allowed + pub voting_start_epoch: Epoch, + /// The epoch from which voting is stopped + pub voting_end_epoch: Epoch, + /// The epoch from which this changes are executed + pub grace_epoch: Epoch, +} + +impl StorageProposal { + /// Check if the proposal can be voted + pub fn can_be_voted( + &self, + current_epoch: Epoch, + is_validator: bool, + ) -> bool { + if is_validator { + self.voting_start_epoch < self.voting_end_epoch + && current_epoch * 3 + <= self.voting_start_epoch + self.voting_end_epoch * 2 + } else { + let valid_start_epoch = current_epoch >= self.voting_start_epoch; + let valid_end_epoch = current_epoch <= self.voting_end_epoch; + valid_start_epoch && valid_end_epoch + } + } + + /// Return the type of tally for the proposal + pub fn get_tally_type(&self) -> TallyType { + TallyType::from(self.r#type.clone()) + } + + /// Return the status of a proposal + pub fn get_status(&self, current_epoch: Epoch) -> ProposalStatus { + if self.voting_start_epoch > self.voting_end_epoch { + ProposalStatus::Pending + } else if self.voting_start_epoch <= current_epoch + && current_epoch <= self.voting_end_epoch + { + ProposalStatus::OnGoing + } else { + ProposalStatus::Ended + } + } + + /// Serialize a proposal to string + pub fn to_string_with_status(&self, current_epoch: Epoch) -> String { + format!( + "Proposal Id: {} + {:2}Type: {} + {:2}Author: {} + {:2}Content: {:?} + {:2}Start Epoch: {} + {:2}End Epoch: {} + {:2}Grace Epoch: {} + {:2}Status: {} + ", + self.id, + "", + self.r#type, + "", + self.author, + "", + self.content, + "", + self.voting_start_epoch, + "", + self.voting_end_epoch, + "", + self.grace_epoch, + "", + self.get_status(current_epoch) + ) + } +} + +impl Display for StorageProposal { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "Proposal Id: {} + {:2}Type: {} + {:2}Author: {} + {:2}Start Epoch: {} + {:2}End Epoch: {} + {:2}Grace Epoch: {} + ", + self.id, + "", + self.r#type, + "", + self.author, + "", + self.voting_start_epoch, + "", + self.voting_end_epoch, + "", + self.grace_epoch + ) + } +} diff --git a/core/src/ledger/governance/storage/vote.rs b/core/src/ledger/governance/storage/vote.rs new file mode 100644 index 0000000000..3ba8ec2ae2 --- /dev/null +++ b/core/src/ledger/governance/storage/vote.rs @@ -0,0 +1,127 @@ +use std::fmt::Display; + +use borsh::{BorshDeserialize, BorshSerialize}; +use serde::{Deserialize, Serialize}; + +use super::super::cli::onchain::ProposalVote; +use super::proposal::ProposalType; + +/// The type of a governance vote with the optional associated Memo +#[derive( + Debug, + Clone, + PartialEq, + BorshSerialize, + BorshDeserialize, + Eq, + Serialize, + Deserialize, +)] +pub enum VoteType { + /// A default vote without Memo + Default, + /// A vote for the PGF stewards + PGFSteward, + /// A vote for a PGF payment proposal + PGFPayment, +} + +#[derive( + Debug, + Clone, + PartialEq, + BorshSerialize, + BorshDeserialize, + Eq, + Serialize, + Deserialize, +)] +/// The vote for a proposal +pub enum StorageProposalVote { + /// Yes + Yay(VoteType), + /// No + Nay, +} + +impl StorageProposalVote { + /// Check if a vote is yay + pub fn is_yay(&self) -> bool { + matches!(self, StorageProposalVote::Yay(_)) + } + + /// Check if vote is of type default + pub fn is_default_vote(&self) -> bool { + matches!( + self, + StorageProposalVote::Yay(VoteType::Default) + | StorageProposalVote::Nay + ) + } + + /// Check if a vote is compatible with a proposal + pub fn is_compatible(&self, proposal_type: &ProposalType) -> bool { + match self { + StorageProposalVote::Yay(vote_type) => proposal_type.eq(vote_type), + StorageProposalVote::Nay => true, + } + } + + /// Create a new vote + pub fn build( + proposal_vote: &ProposalVote, + proposal_type: &ProposalType, + ) -> Option { + match (proposal_vote, proposal_type) { + (ProposalVote::Yay, ProposalType::Default(_)) => { + Some(StorageProposalVote::Yay(VoteType::Default)) + } + (ProposalVote::Yay, ProposalType::PGFSteward(_)) => { + Some(StorageProposalVote::Yay(VoteType::PGFSteward)) + } + (ProposalVote::Yay, ProposalType::PGFPayment(_)) => { + Some(StorageProposalVote::Yay(VoteType::PGFPayment)) + } + (ProposalVote::Nay, ProposalType::Default(_)) => { + Some(StorageProposalVote::Nay) + } + (ProposalVote::Nay, ProposalType::PGFSteward(_)) => { + Some(StorageProposalVote::Nay) + } + (ProposalVote::Nay, ProposalType::PGFPayment(_)) => { + Some(StorageProposalVote::Nay) + } + _ => None, + } + } +} + +impl Display for StorageProposalVote { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + StorageProposalVote::Yay(vote_type) => match vote_type { + VoteType::Default + | VoteType::PGFSteward + | VoteType::PGFPayment => write!(f, "yay"), + }, + + StorageProposalVote::Nay => write!(f, "nay"), + } + } +} + +impl PartialEq for ProposalType { + fn eq(&self, other: &VoteType) -> bool { + match self { + Self::Default(_) => { + matches!(other, VoteType::Default) + } + Self::PGFSteward(_) => { + matches!(other, VoteType::PGFSteward) + } + Self::PGFPayment(_) => { + matches!(other, VoteType::PGFPayment) + } + } + } +} diff --git a/core/src/ledger/governance/utils.rs b/core/src/ledger/governance/utils.rs new file mode 100644 index 0000000000..30df25e3fb --- /dev/null +++ b/core/src/ledger/governance/utils.rs @@ -0,0 +1,291 @@ +use std::collections::HashMap; +use std::fmt::Display; + +use borsh::{BorshDeserialize, BorshSerialize}; + +use super::cli::offline::OfflineVote; +use super::storage::proposal::ProposalType; +use super::storage::vote::StorageProposalVote; +use crate::types::address::Address; +use crate::types::storage::Epoch; +use crate::types::token; + +/// Proposal status +pub enum ProposalStatus { + /// Pending proposal status + Pending, + /// Ongoing proposal status + OnGoing, + /// Ended proposal status + Ended, +} + +impl Display for ProposalStatus { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ProposalStatus::Pending => write!(f, "pending"), + ProposalStatus::OnGoing => write!(f, "on-going"), + ProposalStatus::Ended => write!(f, "ended"), + } + } +} + +/// Alias to comulate voting power +pub type VotePower = token::Amount; + +/// Structure rappresenting a proposal vote +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] +pub struct Vote { + /// Field holding the address of the validator + pub validator: Address, + /// Field holding the address of the delegator + pub delegator: Address, + /// Field holding vote data + pub data: StorageProposalVote, +} + +impl Vote { + /// Check if a vote is from a validator + pub fn is_validator(&self) -> bool { + self.validator.eq(&self.delegator) + } +} + +/// Rappresent a tally type +pub enum TallyType { + /// Rappresent a tally type for proposal requiring 2/3 of the votes + TwoThird, + /// Rappresent a tally type for proposal requiring 1/3 of the votes + OneThird, + /// Rappresent a tally type for proposal requiring less than 1/3 of the + /// votes to be nay + LessOneThirdNay, +} + +impl From for TallyType { + fn from(proposal_type: ProposalType) -> Self { + match proposal_type { + ProposalType::Default(_) => TallyType::TwoThird, + ProposalType::PGFSteward(_) => TallyType::TwoThird, + ProposalType::PGFPayment(_) => TallyType::LessOneThirdNay, + } + } +} + +/// The result of a proposal +pub enum TallyResult { + /// Proposal was accepted with the associated value + Passed, + /// Proposal was rejected + Rejected, +} + +impl Display for TallyResult { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + TallyResult::Passed => write!(f, "passed"), + TallyResult::Rejected => write!(f, "rejected"), + } + } +} + +impl TallyResult { + /// Create a new tally result + pub fn new( + tally_type: &TallyType, + yay_voting_power: VotePower, + nay_voting_power: VotePower, + total_voting_power: VotePower, + ) -> Self { + let passed = match tally_type { + TallyType::TwoThird => { + let at_least_two_third_voted = yay_voting_power + + nay_voting_power + >= total_voting_power / 3 * 2; + let at_last_half_voted_yay = + yay_voting_power > nay_voting_power; + at_least_two_third_voted && at_last_half_voted_yay + } + TallyType::OneThird => { + let at_least_two_third_voted = yay_voting_power + + nay_voting_power + >= total_voting_power / 3; + let at_last_half_voted_yay = + yay_voting_power > nay_voting_power; + at_least_two_third_voted && at_last_half_voted_yay + } + TallyType::LessOneThirdNay => { + nay_voting_power <= total_voting_power / 3 + } + }; + + if passed { Self::Passed } else { Self::Rejected } + } +} + +/// The result with votes of a proposal +pub struct ProposalResult { + /// The result of a proposal + pub result: TallyResult, + /// The total voting power during the proposal tally + pub total_voting_power: VotePower, + /// The total voting power from yay votes + pub total_yay_power: VotePower, + /// The total voting power from nay votes (unused at the moment) + pub total_nay_power: VotePower, +} + +impl Display for ProposalResult { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let percentage = self + .total_yay_power + .checked_div(self.total_voting_power) + .unwrap_or_default(); + + write!( + f, + "{} with {} yay votes and {} nay votes ({:.2}%)", + self.result, + self.total_yay_power.to_string_native(), + self.total_nay_power.to_string_native(), + percentage + .checked_mul(token::Amount::from_u64(100)) + .unwrap_or_default() + .to_string_native() + ) + } +} + +impl ProposalResult { + /// Return true if two third of total voting power voted nay + pub fn two_third_nay(&self) -> bool { + self.total_nay_power >= (self.total_voting_power / 3) * 2 + } +} + +/// /// General rappresentation of a vote +pub enum TallyVote { + /// Rappresent a vote for a proposal onchain + OnChain(StorageProposalVote), + /// Rappresent a vote for a proposal offline + Offline(OfflineVote), +} + +impl From for TallyVote { + fn from(vote: StorageProposalVote) -> Self { + Self::OnChain(vote) + } +} + +impl From for TallyVote { + fn from(vote: OfflineVote) -> Self { + Self::Offline(vote) + } +} + +impl TallyVote { + /// Check if a vote is yay + pub fn is_yay(&self) -> bool { + match self { + TallyVote::OnChain(vote) => vote.is_yay(), + TallyVote::Offline(vote) => vote.is_yay(), + } + } + + /// Check if two votes are equal + pub fn is_same_side(&self, other: &TallyVote) -> bool { + let both_yay = self.is_yay() && other.is_yay(); + let both_nay = !self.is_yay() && !other.is_yay(); + + both_yay || !both_nay + } +} + +/// Proposal structure holding votes information necessary to compute the +/// outcome +pub struct ProposalVotes { + /// Map from validator address to vote + pub validators_vote: HashMap, + /// Map from validator to their voting power + pub validator_voting_power: HashMap, + /// Map from delegation address to their vote + pub delegators_vote: HashMap, + /// Map from delegator address to the corresponding validator voting power + pub delegator_voting_power: HashMap>, +} + +/// Compute the result of a proposal +pub fn compute_proposal_result( + votes: ProposalVotes, + total_voting_power: VotePower, + tally_at: TallyType, +) -> ProposalResult { + let mut yay_voting_power = VotePower::default(); + let mut nay_voting_power = VotePower::default(); + + for (address, vote_power) in votes.validator_voting_power { + let vote_type = votes.validators_vote.get(&address); + if let Some(vote) = vote_type { + if vote.is_yay() { + yay_voting_power += vote_power; + } else { + nay_voting_power += vote_power; + } + } + } + + for (delegator, degalations) in votes.delegator_voting_power { + let delegator_vote = match votes.delegators_vote.get(&delegator) { + Some(vote) => vote, + None => continue, + }; + for (validator, voting_power) in degalations { + let validator_vote = votes.validators_vote.get(&validator); + if let Some(validator_vote) = validator_vote { + if !validator_vote.is_same_side(delegator_vote) { + if delegator_vote.is_yay() { + yay_voting_power += voting_power; + nay_voting_power -= voting_power; + } else { + nay_voting_power += voting_power; + yay_voting_power -= voting_power; + } + } + } else if delegator_vote.is_yay() { + yay_voting_power += voting_power; + } else { + nay_voting_power += voting_power; + } + } + } + + let tally_result = TallyResult::new( + &tally_at, + yay_voting_power, + nay_voting_power, + total_voting_power, + ); + + ProposalResult { + result: tally_result, + total_voting_power, + total_yay_power: yay_voting_power, + total_nay_power: nay_voting_power, + } +} + +/// Calculate the valid voting window for validator given a proposal epoch +/// details +pub fn is_valid_validator_voting_period( + current_epoch: Epoch, + voting_start_epoch: Epoch, + voting_end_epoch: Epoch, +) -> bool { + if voting_start_epoch >= voting_end_epoch { + false + } else { + let duration = voting_end_epoch - voting_start_epoch; + let two_third_duration = (duration / 3) * 2; + current_epoch <= voting_start_epoch + two_third_duration + } +} diff --git a/core/src/ledger/ibc/context/common.rs b/core/src/ledger/ibc/context/common.rs index 4c96c034b5..c3e9b1d08d 100644 --- a/core/src/ledger/ibc/context/common.rs +++ b/core/src/ledger/ibc/context/common.rs @@ -22,12 +22,12 @@ use crate::ibc::core::ics24_host::identifier::{ClientId, ConnectionId}; use crate::ibc::core::ics24_host::path::{ ChannelEndPath, ClientConsensusStatePath, CommitmentPath, Path, SeqSendPath, }; +use crate::ibc::core::timestamp::Timestamp; use crate::ibc::core::ContextError; #[cfg(any(feature = "ibc-mocks-abcipp", feature = "ibc-mocks"))] use crate::ibc::mock::client_state::MockClientState; #[cfg(any(feature = "ibc-mocks-abcipp", feature = "ibc-mocks"))] use crate::ibc::mock::consensus_state::MockConsensusState; -use crate::ibc::timestamp::Timestamp; use crate::ibc_proto::google::protobuf::Any; use crate::ibc_proto::protobuf::Protobuf; use crate::ledger::ibc::storage; @@ -48,11 +48,11 @@ pub trait IbcCommonContext: IbcStorageContext { })?; self.decode_client_state(any) } - Ok(None) => { - Err(ContextError::ClientError(ClientError::ClientNotFound { + Ok(None) => Err(ContextError::ClientError( + ClientError::ClientStateNotFound { client_id: client_id.clone(), - })) - } + }, + )), Err(_) => Err(ContextError::ClientError(ClientError::Other { description: format!( "Reading the client state failed: ID {}", @@ -145,11 +145,11 @@ pub trait IbcCommonContext: IbcStorageContext { }) }), Ok(None) => { - let port_channel_id = + let (port_id, channel_id) = storage::port_channel_id(&key).expect("invalid key"); Err(ContextError::ChannelError(ChannelError::ChannelNotFound { - channel_id: port_channel_id.channel_id, - port_id: port_channel_id.port_id, + channel_id, + port_id, })) } Err(_) => Err(ContextError::ChannelError(ChannelError::Other { diff --git a/core/src/ledger/ibc/context/execution.rs b/core/src/ledger/ibc/context/execution.rs index ae84afa614..ec0708ce2a 100644 --- a/core/src/ledger/ibc/context/execution.rs +++ b/core/src/ledger/ibc/context/execution.rs @@ -3,8 +3,8 @@ use borsh::{BorshDeserialize, BorshSerialize}; use super::super::{IbcActions, IbcCommonContext}; +use crate::ibc::core::events::IbcEvent; use crate::ibc::core::ics02_client::client_state::ClientState; -use crate::ibc::core::ics02_client::client_type::ClientType; use crate::ibc::core::ics02_client::consensus_state::ConsensusState; use crate::ibc::core::ics02_client::error::ClientError; use crate::ibc::core::ics03_connection::connection::ConnectionEnd; @@ -18,12 +18,11 @@ use crate::ibc::core::ics04_channel::packet::{Receipt, Sequence}; use crate::ibc::core::ics24_host::identifier::{ClientId, ConnectionId}; use crate::ibc::core::ics24_host::path::{ AckPath, ChannelEndPath, ClientConnectionPath, ClientConsensusStatePath, - ClientStatePath, ClientTypePath, CommitmentPath, ConnectionPath, Path, - ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, + ClientStatePath, CommitmentPath, ConnectionPath, Path, ReceiptPath, + SeqAckPath, SeqRecvPath, SeqSendPath, }; +use crate::ibc::core::timestamp::Timestamp; use crate::ibc::core::{ContextError, ExecutionContext, ValidationContext}; -use crate::ibc::events::IbcEvent; -use crate::ibc::timestamp::Timestamp; use crate::ibc::Height; use crate::ibc_proto::protobuf::Protobuf; use crate::ledger::ibc::storage; @@ -33,25 +32,6 @@ impl ExecutionContext for IbcActions<'_, C> where C: IbcCommonContext, { - fn store_client_type( - &mut self, - client_type_path: ClientTypePath, - client_type: ClientType, - ) -> Result<(), ContextError> { - let path = Path::ClientType(client_type_path); - let key = storage::ibc_key(path.to_string()) - .expect("Creating a key for the client state shouldn't fail"); - let bytes = client_type.as_str().as_bytes().to_vec(); - self.ctx.borrow_mut().write(&key, bytes).map_err(|_| { - ContextError::ClientError(ClientError::Other { - description: format!( - "Writing the client state failed: Key {}", - key - ), - }) - }) - } - fn store_client_state( &mut self, client_state_path: ClientStatePath, @@ -60,7 +40,7 @@ where let path = Path::ClientState(client_state_path); let key = storage::ibc_key(path.to_string()) .expect("Creating a key for the client state shouldn't fail"); - let bytes = client_state.encode_vec().expect("encoding shouldn't fail"); + let bytes = client_state.encode_vec(); self.ctx.borrow_mut().write(&key, bytes).map_err(|_| { ContextError::ClientError(ClientError::Other { description: format!( @@ -79,9 +59,7 @@ where let path = Path::ClientConsensusState(consensus_state_path); let key = storage::ibc_key(path.to_string()) .expect("Creating a key for the client state shouldn't fail"); - let bytes = consensus_state - .encode_vec() - .expect("encoding shouldn't fail"); + let bytes = consensus_state.encode_vec(); self.ctx.borrow_mut().write(&key, bytes).map_err(|_| { ContextError::ClientError(ClientError::Other { description: format!( @@ -140,7 +118,7 @@ where host_height: Height, ) -> Result<(), ContextError> { let key = storage::client_update_height_key(&client_id); - let bytes = host_height.encode_vec().expect("encoding shouldn't fail"); + let bytes = host_height.encode_vec(); self.ctx.borrow_mut().write(&key, bytes).map_err(|_| { ContextError::ClientError(ClientError::Other { description: format!( @@ -159,9 +137,7 @@ where let path = Path::Connection(connection_path.clone()); let key = storage::ibc_key(path.to_string()) .expect("Creating a key for the client state shouldn't fail"); - let bytes = connection_end - .encode_vec() - .expect("encoding shouldn't fail"); + let bytes = connection_end.encode_vec(); self.ctx.borrow_mut().write(&key, bytes).map_err(|_| { ContextError::ConnectionError(ConnectionError::Other { description: format!( @@ -321,7 +297,7 @@ where let path = Path::ChannelEnd(path.clone()); let key = storage::ibc_key(path.to_string()) .expect("Creating a key for the client state shouldn't fail"); - let bytes = channel_end.encode_vec().expect("encoding shouldn't fail"); + let bytes = channel_end.encode_vec(); self.ctx.borrow_mut().write(&key, bytes).map_err(|_| { ContextError::ChannelError(ChannelError::Other { description: format!( diff --git a/core/src/ledger/ibc/context/router.rs b/core/src/ledger/ibc/context/router.rs index 62d676c3a2..dfa0d9be82 100644 --- a/core/src/ledger/ibc/context/router.rs +++ b/core/src/ledger/ibc/context/router.rs @@ -3,9 +3,8 @@ use std::rc::Rc; use super::super::{IbcActions, IbcCommonContext}; -use crate::ibc::core::context::Router; use crate::ibc::core::ics24_host::identifier::PortId; -use crate::ibc::core::ics26_routing::context::{Module, ModuleId}; +use crate::ibc::core::router::{Module, ModuleId, Router}; impl Router for IbcActions<'_, C> where diff --git a/core/src/ledger/ibc/context/transfer_mod.rs b/core/src/ledger/ibc/context/transfer_mod.rs index 8280f7c36b..0684432dab 100644 --- a/core/src/ledger/ibc/context/transfer_mod.rs +++ b/core/src/ledger/ibc/context/transfer_mod.rs @@ -3,7 +3,6 @@ use std::cell::RefCell; use std::fmt::Debug; use std::rc::Rc; -use std::str::FromStr; use super::common::IbcCommonContext; use crate::ibc::applications::transfer::coin::PrefixedCoin; @@ -22,6 +21,7 @@ use crate::ibc::applications::transfer::context::{ use crate::ibc::applications::transfer::denom::PrefixedDenom; use crate::ibc::applications::transfer::error::TokenTransferError; use crate::ibc::applications::transfer::MODULE_ID_STR; +use crate::ibc::core::events::IbcEvent; use crate::ibc::core::ics02_client::client_state::ClientState; use crate::ibc::core::ics02_client::consensus_state::ConsensusState; use crate::ibc::core::ics03_connection::connection::ConnectionEnd; @@ -33,9 +33,9 @@ use crate::ibc::core::ics04_channel::context::{ SendPacketExecutionContext, SendPacketValidationContext, }; use crate::ibc::core::ics04_channel::error::{ChannelError, PacketError}; -use crate::ibc::core::ics04_channel::handler::ModuleExtras; -use crate::ibc::core::ics04_channel::msgs::acknowledgement::Acknowledgement; -use crate::ibc::core::ics04_channel::packet::{Packet, Sequence}; +use crate::ibc::core::ics04_channel::packet::{ + Acknowledgement, Packet, Sequence, +}; use crate::ibc::core::ics04_channel::Version; use crate::ibc::core::ics24_host::identifier::{ ChannelId, ClientId, ConnectionId, PortId, @@ -43,10 +43,9 @@ use crate::ibc::core::ics24_host::identifier::{ use crate::ibc::core::ics24_host::path::{ ChannelEndPath, ClientConsensusStatePath, CommitmentPath, SeqSendPath, }; -use crate::ibc::core::ics26_routing::context::{Module, ModuleId}; +use crate::ibc::core::router::{Module, ModuleExtras, ModuleId}; use crate::ibc::core::ContextError; -use crate::ibc::events::IbcEvent; -use crate::ibc::signer::Signer; +use crate::ibc::Signer; use crate::ledger::ibc::storage; use crate::types::address::{Address, InternalAddress}; use crate::types::token; @@ -81,7 +80,7 @@ where /// Get the module ID pub fn module_id(&self) -> ModuleId { - ModuleId::from_str(MODULE_ID_STR).expect("should be parsable") + ModuleId::new(MODULE_ID_STR.to_string()) } } @@ -593,7 +592,7 @@ pub mod testing { impl DummyTransferModule { /// Get the module ID pub fn module_id(&self) -> ModuleId { - ModuleId::from_str(MODULE_ID_STR).expect("should be parsable") + ModuleId::new(MODULE_ID_STR.to_string()) } } diff --git a/core/src/ledger/ibc/context/validation.rs b/core/src/ledger/ibc/context/validation.rs index 9e13820883..9ad3dd2654 100644 --- a/core/src/ledger/ibc/context/validation.rs +++ b/core/src/ledger/ibc/context/validation.rs @@ -4,8 +4,6 @@ use prost::Message; use super::super::{IbcActions, IbcCommonContext}; use crate::ibc::clients::ics07_tendermint::consensus_state::ConsensusState as TmConsensusState; -#[cfg(any(feature = "ibc-mocks-abcipp", feature = "ibc-mocks"))] -use crate::ibc::core::ics02_client::client_state::downcast_client_state; use crate::ibc::core::ics02_client::client_state::ClientState; use crate::ibc::core::ics02_client::consensus_state::ConsensusState; use crate::ibc::core::ics02_client::error::ClientError; @@ -25,12 +23,12 @@ use crate::ibc::core::ics24_host::path::{ AckPath, ChannelEndPath, ClientConsensusStatePath, CommitmentPath, Path, ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; +use crate::ibc::core::timestamp::Timestamp; use crate::ibc::core::{ContextError, ValidationContext}; use crate::ibc::hosts::tendermint::ValidateSelfClientContext; #[cfg(any(feature = "ibc-mocks-abcipp", feature = "ibc-mocks"))] use crate::ibc::mock::client_state::MockClientState; -use crate::ibc::timestamp::Timestamp; -use crate::ibc::Height; +use crate::ibc::{Height, Signer}; use crate::ibc_proto::google::protobuf::Any; use crate::ibc_proto::protobuf::Protobuf; use crate::ledger::ibc::storage; @@ -260,14 +258,8 @@ where ) -> Result<(), ContextError> { #[cfg(any(feature = "ibc-mocks-abcipp", feature = "ibc-mocks"))] { - let client_state = self - .decode_client_state(counterparty_client_state.clone()) - .map_err(|_| ClientError::Other { - description: "Decoding the client state failed".to_string(), - })?; - - if let Some(_mock) = - downcast_client_state::(client_state.as_ref()) + if MockClientState::try_from(counterparty_client_state.clone()) + .is_ok() { return Ok(()); } @@ -496,6 +488,14 @@ where _ => unreachable!("The parameter should be initialized"), } } + + fn validate_message_signer( + &self, + _signer: &Signer, + ) -> Result<(), ContextError> { + // The signer of a transaction should be validated + Ok(()) + } } impl ValidateSelfClientContext for IbcActions<'_, C> diff --git a/core/src/ledger/ibc/mod.rs b/core/src/ledger/ibc/mod.rs index b56e8ce54a..75ff665914 100644 --- a/core/src/ledger/ibc/mod.rs +++ b/core/src/ledger/ibc/mod.rs @@ -9,7 +9,6 @@ use std::fmt::Debug; use std::rc::Rc; use std::time::Duration; -use borsh::BorshDeserialize; pub use context::common::IbcCommonContext; pub use context::storage::{IbcStorageContext, ProofSpec}; pub use context::transfer_mod::{ModuleWrapper, TransferModule}; @@ -18,21 +17,16 @@ use thiserror::Error; use crate::ibc::applications::transfer::denom::TracePrefix; use crate::ibc::applications::transfer::error::TokenTransferError; -use crate::ibc::applications::transfer::msgs::transfer::{ - MsgTransfer, TYPE_URL as MSG_TRANSFER_TYPE_URL, -}; +use crate::ibc::applications::transfer::msgs::transfer::MsgTransfer; use crate::ibc::applications::transfer::packet::PacketData; -use crate::ibc::applications::transfer::relay::send_transfer::{ +use crate::ibc::applications::transfer::{ send_transfer_execute, send_transfer_validate, }; -use crate::ibc::core::context::Router; use crate::ibc::core::ics04_channel::msgs::PacketMsg; use crate::ibc::core::ics23_commitment::specs::ProofSpecs; use crate::ibc::core::ics24_host::identifier::{ChainId as IbcChainId, PortId}; -use crate::ibc::core::ics26_routing::context::{Module, ModuleId}; -use crate::ibc::core::ics26_routing::error::RouterError; -use crate::ibc::core::ics26_routing::msgs::MsgEnvelope; -use crate::ibc::core::{execute, validate}; +use crate::ibc::core::router::{Module, ModuleId, Router}; +use crate::ibc::core::{execute, validate, MsgEnvelope, RouterError}; use crate::ibc_proto::google::protobuf::Any; use crate::types::chain::ChainId; @@ -115,66 +109,32 @@ where /// Execute according to the message in an IBC transaction or VP pub fn execute(&mut self, tx_data: &[u8]) -> Result<(), Error> { - let msg = Any::decode(tx_data).map_err(Error::DecodingData)?; - match msg.type_url.as_str() { - MSG_TRANSFER_TYPE_URL => { - let msg = - MsgTransfer::try_from(msg).map_err(Error::TokenTransfer)?; + let any_msg = Any::decode(tx_data).map_err(Error::DecodingData)?; + match MsgTransfer::try_from(any_msg.clone()) { + Ok(msg) => { let port_id = msg.port_id_on_a.clone(); match self.get_route_mut_by_port(&port_id) { Some(_module) => { let mut module = TransferModule::new(self.ctx.clone()); - // restore the denom if it is hashed - let msg = self.restore_denom(msg)?; send_transfer_execute(&mut module, msg) .map_err(Error::TokenTransfer) } None => Err(Error::NoModule), } } - _ => { - execute(self, msg.clone()).map_err(Error::Execution)?; + Err(_) => { + let envelope = + MsgEnvelope::try_from(any_msg).map_err(Error::Execution)?; + execute(self, envelope.clone()).map_err(Error::Execution)?; // the current ibc-rs execution doesn't store the denom for the // token hash when transfer with MsgRecvPacket - self.store_denom(msg) + self.store_denom(envelope) } } } - /// Restore the denom when it is hashed - fn restore_denom(&self, msg: MsgTransfer) -> Result { - let mut msg = msg; - // lookup the original denom with the IBC token hash - if let Some(token_hash) = - storage::token_hash_from_denom(&msg.token.denom).map_err(|e| { - Error::Denom(format!("Invalid denom: error {}", e)) - })? - { - let denom_key = storage::ibc_denom_key(token_hash); - let denom = match self.ctx.borrow().read(&denom_key) { - Ok(Some(v)) => String::try_from_slice(&v[..]).map_err(|e| { - Error::Denom(format!( - "Decoding the denom string failed: {}", - e - )) - })?, - _ => { - return Err(Error::Denom(format!( - "No original denom: denom_key {}", - denom_key - ))); - } - }; - msg.token.denom = denom; - } - Ok(msg) - } - /// Store the denom when transfer with MsgRecvPacket - fn store_denom(&mut self, msg: Any) -> Result<(), Error> { - let envelope = MsgEnvelope::try_from(msg).map_err(|e| { - Error::Denom(format!("Decoding the message failed: {}", e)) - })?; + fn store_denom(&mut self, envelope: MsgEnvelope) -> Result<(), Error> { match envelope { MsgEnvelope::Packet(PacketMsg::Recv(msg)) => { let data = match serde_json::from_slice::( @@ -205,24 +165,24 @@ where /// Validate according to the message in IBC VP pub fn validate(&self, tx_data: &[u8]) -> Result<(), Error> { - let msg = Any::decode(tx_data).map_err(Error::DecodingData)?; - match msg.type_url.as_str() { - MSG_TRANSFER_TYPE_URL => { - let msg = - MsgTransfer::try_from(msg).map_err(Error::TokenTransfer)?; + let any_msg = Any::decode(tx_data).map_err(Error::DecodingData)?; + match MsgTransfer::try_from(any_msg.clone()) { + Ok(msg) => { let port_id = msg.port_id_on_a.clone(); match self.get_route_by_port(&port_id) { Some(_module) => { let module = TransferModule::new(self.ctx.clone()); - // restore the denom if it is hashed - let msg = self.restore_denom(msg)?; send_transfer_validate(&module, msg) .map_err(Error::TokenTransfer) } None => Err(Error::NoModule), } } - _ => validate(self, msg).map_err(Error::Validation), + Err(_) => { + let envelope = MsgEnvelope::try_from(any_msg) + .map_err(Error::Validation)?; + validate(self, envelope).map_err(Error::Validation) + } } } } diff --git a/core/src/ledger/ibc/storage.rs b/core/src/ledger/ibc/storage.rs index 1a47680f00..9a80766c47 100644 --- a/core/src/ledger/ibc/storage.rs +++ b/core/src/ledger/ibc/storage.rs @@ -8,14 +8,13 @@ use thiserror::Error; use crate::ibc::core::ics02_client::height::Height; use crate::ibc::core::ics04_channel::packet::Sequence; use crate::ibc::core::ics24_host::identifier::{ - ChannelId, ClientId, ConnectionId, PortChannelId, PortId, + ChannelId, ClientId, ConnectionId, PortId, }; use crate::ibc::core::ics24_host::path::{ AckPath, ChannelEndPath, ClientConnectionPath, ClientConsensusStatePath, - ClientStatePath, ClientTypePath, CommitmentPath, ConnectionPath, PortPath, + ClientStatePath, CommitmentPath, ConnectionPath, Path, PortPath, ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; -use crate::ibc::core::ics24_host::Path; use crate::types::address::{Address, InternalAddress, HASH_HEX_LEN}; use crate::types::storage::{self, DbKeySeg, Key, KeySeg}; @@ -70,13 +69,6 @@ pub fn channel_counter_key() -> Key { .expect("Creating a key for the channel counter shouldn't fail") } -/// Returns a key for the client type -pub fn client_type_key(client_id: &ClientId) -> Key { - let path = Path::ClientType(ClientTypePath(client_id.clone())); - ibc_key(path.to_string()) - .expect("Creating a key for the client state shouldn't fail") -} - /// Returns a key for the client state pub fn client_state_key(client_id: &ClientId) -> Key { let path = Path::ClientState(ClientStatePath(client_id.clone())); @@ -117,11 +109,9 @@ pub fn connection_key(conn_id: &ConnectionId) -> Key { } /// Returns a key for the channel end -pub fn channel_key(port_channel_id: &PortChannelId) -> Key { - let path = Path::ChannelEnd(ChannelEndPath( - port_channel_id.port_id.clone(), - port_channel_id.channel_id.clone(), - )); +pub fn channel_key(port_id: &PortId, channel_id: &ChannelId) -> Key { + let path = + Path::ChannelEnd(ChannelEndPath(port_id.clone(), channel_id.clone())); ibc_key(path.to_string()) .expect("Creating a key for the channel shouldn't fail") } @@ -141,31 +131,22 @@ pub fn port_key(port_id: &PortId) -> Key { } /// Returns a key for nextSequenceSend -pub fn next_sequence_send_key(port_channel_id: &PortChannelId) -> Key { - let path = Path::SeqSend(SeqSendPath( - port_channel_id.port_id.clone(), - port_channel_id.channel_id.clone(), - )); +pub fn next_sequence_send_key(port_id: &PortId, channel_id: &ChannelId) -> Key { + let path = Path::SeqSend(SeqSendPath(port_id.clone(), channel_id.clone())); ibc_key(path.to_string()) .expect("Creating a key for nextSequenceSend shouldn't fail") } /// Returns a key for nextSequenceRecv -pub fn next_sequence_recv_key(port_channel_id: &PortChannelId) -> Key { - let path = Path::SeqRecv(SeqRecvPath( - port_channel_id.port_id.clone(), - port_channel_id.channel_id.clone(), - )); +pub fn next_sequence_recv_key(port_id: &PortId, channel_id: &ChannelId) -> Key { + let path = Path::SeqRecv(SeqRecvPath(port_id.clone(), channel_id.clone())); ibc_key(path.to_string()) .expect("Creating a key for nextSequenceRecv shouldn't fail") } /// Returns a key for nextSequenceAck -pub fn next_sequence_ack_key(port_channel_id: &PortChannelId) -> Key { - let path = Path::SeqAck(SeqAckPath( - port_channel_id.port_id.clone(), - port_channel_id.channel_id.clone(), - )); +pub fn next_sequence_ack_key(port_id: &PortId, channel_id: &ChannelId) -> Key { + let path = Path::SeqAck(SeqAckPath(port_id.clone(), channel_id.clone())); ibc_key(path.to_string()) .expect("Creating a key for nextSequenceAck shouldn't fail") } @@ -295,7 +276,7 @@ pub fn connection_id(key: &Key) -> Result { /// Returns a pair of port ID and channel ID from the given channel/sequence key /// `#IBC//ports//channels/` -pub fn port_channel_id(key: &Key) -> Result { +pub fn port_channel_id(key: &Key) -> Result<(PortId, ChannelId)> { match &key.segments[..] { [ DbKeySeg::AddressSeg(addr), @@ -316,10 +297,7 @@ pub fn port_channel_id(key: &Key) -> Result { .map_err(|e| Error::InvalidKey(e.to_string()))?; let channel_id = ChannelId::from_str(&channel.raw()) .map_err(|e| Error::InvalidKey(e.to_string()))?; - Ok(PortChannelId { - port_id, - channel_id, - }) + Ok((port_id, channel_id)) } _ => Err(Error::InvalidKey(format!( "The key doesn't have port ID and channel ID: Key {}", diff --git a/core/src/ledger/mod.rs b/core/src/ledger/mod.rs index 89b8105551..9a84fbc126 100644 --- a/core/src/ledger/mod.rs +++ b/core/src/ledger/mod.rs @@ -6,8 +6,8 @@ pub mod governance; #[cfg(any(feature = "abciplus", feature = "abcipp"))] pub mod ibc; pub mod parameters; +pub mod pgf; pub mod replay_protection; -pub mod slash_fund; pub mod storage; pub mod storage_api; pub mod testnet_pow; diff --git a/core/src/ledger/parameters/mod.rs b/core/src/ledger/parameters/mod.rs index c507e55d49..03d27fa2da 100644 --- a/core/src/ledger/parameters/mod.rs +++ b/core/src/ledger/parameters/mod.rs @@ -46,6 +46,8 @@ pub struct Parameters { pub implicit_vp_code_hash: Hash, /// Expected number of epochs per year (read only) pub epochs_per_year: u64, + /// Maximum number of signature per transaction + pub max_signatures_per_transaction: u8, /// PoS gain p (read only) pub pos_gain_p: Dec, /// PoS gain d (read only) @@ -117,6 +119,7 @@ impl Parameters { tx_whitelist, implicit_vp_code_hash, epochs_per_year, + max_signatures_per_transaction, pos_gain_p, pos_gain_d, staked_ratio, @@ -168,6 +171,13 @@ impl Parameters { let epochs_per_year_key = storage::get_epochs_per_year_key(); storage.write(&epochs_per_year_key, epochs_per_year)?; + let max_signatures_per_transaction_key = + storage::get_max_signatures_per_transaction_key(); + storage.write( + &max_signatures_per_transaction_key, + max_signatures_per_transaction, + )?; + let pos_gain_p_key = storage::get_pos_gain_p_key(); storage.write(&pos_gain_p_key, pos_gain_p)?; @@ -197,6 +207,17 @@ impl Parameters { } } +/// Get the max signatures per transactio parameter +pub fn max_signatures_per_transaction( + storage: &S, +) -> storage_api::Result> +where + S: StorageRead, +{ + let key = storage::get_max_signatures_per_transaction_key(); + storage.read(&key) +} + /// Update the max_expected_time_per_block parameter in storage. Returns the /// parameters and gas cost. pub fn update_max_expected_time_per_block_parameter( @@ -340,6 +361,20 @@ where storage.write_bytes(&key, implicit_vp) } +/// Update the max signatures per transaction storage parameter +pub fn update_max_signature_per_tx( + storage: &mut S, + value: u8, +) -> storage_api::Result<()> +where + S: StorageRead + StorageWrite, +{ + let key = storage::get_max_signatures_per_transaction_key(); + // Using `fn write_bytes` here, because implicit_vp doesn't need to be + // encoded, it's bytes already. + storage.write(&key, value) +} + /// Read the the epoch duration parameter from store pub fn read_epoch_duration_parameter( storage: &S, @@ -434,6 +469,15 @@ where .ok_or(ReadError::ParametersMissing) .into_storage_result()?; + // read the maximum signatures per transaction + let max_signatures_per_transaction_key = + storage::get_max_signatures_per_transaction_key(); + let value: Option = + storage.read(&max_signatures_per_transaction_key)?; + let max_signatures_per_transaction: u8 = value + .ok_or(ReadError::ParametersMissing) + .into_storage_result()?; + // read PoS gain P let pos_gain_p_key = storage::get_pos_gain_p_key(); let value = storage.read(&pos_gain_p_key)?; @@ -478,6 +522,7 @@ where tx_whitelist, implicit_vp_code_hash, epochs_per_year, + max_signatures_per_transaction, pos_gain_p, pos_gain_d, staked_ratio, diff --git a/core/src/ledger/parameters/storage.rs b/core/src/ledger/parameters/storage.rs index 94498e3578..d32b1d221f 100644 --- a/core/src/ledger/parameters/storage.rs +++ b/core/src/ledger/parameters/storage.rs @@ -44,6 +44,7 @@ struct Keys { max_proposal_bytes: &'static str, faucet_account: &'static str, wrapper_tx_fees: &'static str, + max_signatures_per_transaction: &'static str, } /// Returns if the key is a parameter key. @@ -183,3 +184,8 @@ pub fn get_faucet_account_key() -> Key { pub fn get_wrapper_tx_fees_key() -> Key { get_wrapper_tx_fees_key_at_addr(ADDRESS) } + +/// Storage key used for the max signatures per transaction key +pub fn get_max_signatures_per_transaction_key() -> Key { + get_max_signatures_per_transaction_key_at_addr(ADDRESS) +} diff --git a/core/src/ledger/slash_fund/mod.rs b/core/src/ledger/pgf/mod.rs similarity index 55% rename from core/src/ledger/slash_fund/mod.rs rename to core/src/ledger/pgf/mod.rs index 7a7d53963b..a36621e49e 100644 --- a/core/src/ledger/slash_fund/mod.rs +++ b/core/src/ledger/pgf/mod.rs @@ -1,8 +1,11 @@ -//! SlashFund library code +//! Pgf library code use crate::types::address::{Address, InternalAddress}; -/// Internal SlashFund address -pub const ADDRESS: Address = Address::Internal(InternalAddress::SlashFund); - +/// Pgf parameters +pub mod parameters; +/// Pgf storage pub mod storage; + +/// The Pgf internal address +pub const ADDRESS: Address = Address::Internal(InternalAddress::Pgf); diff --git a/core/src/ledger/pgf/parameters.rs b/core/src/ledger/pgf/parameters.rs new file mode 100644 index 0000000000..f7e33f06a2 --- /dev/null +++ b/core/src/ledger/pgf/parameters.rs @@ -0,0 +1,63 @@ +use std::collections::BTreeSet; + +use borsh::{BorshDeserialize, BorshSerialize}; + +use super::storage::keys as pgf_storage; +use crate::ledger::storage_api::{self, StorageRead, StorageWrite}; +use crate::types::address::Address; +use crate::types::dec::Dec; + +#[derive( + Clone, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + BorshSerialize, + BorshDeserialize, +)] +/// Pgf parameter structure +pub struct PgfParameters { + /// The set of stewards + pub stewards: BTreeSet
, + /// The pgf funding inflation rate + pub pgf_inflation_rate: Dec, + /// The pgf stewards inflation rate + pub stewards_inflation_rate: Dec, +} + +impl Default for PgfParameters { + fn default() -> Self { + Self { + stewards: BTreeSet::default(), + pgf_inflation_rate: Dec::new(10, 2).unwrap(), + stewards_inflation_rate: Dec::new(1, 2).unwrap(), + } + } +} + +impl PgfParameters { + /// Initialize governance parameters into storage + pub fn init_storage(&self, storage: &mut S) -> storage_api::Result<()> + where + S: StorageRead + StorageWrite, + { + let Self { + stewards, + pgf_inflation_rate, + stewards_inflation_rate, + } = self; + + let stewards_key = pgf_storage::get_stewards_key(); + storage.write(&stewards_key, stewards)?; + + let pgf_inflation_rate_key = pgf_storage::get_pgf_inflation_rate_key(); + storage.write(&pgf_inflation_rate_key, pgf_inflation_rate)?; + + let steward_inflation_rate_key = + pgf_storage::get_steward_inflation_rate_key(); + storage.write(&steward_inflation_rate_key, stewards_inflation_rate) + } +} diff --git a/core/src/ledger/pgf/storage/keys.rs b/core/src/ledger/pgf/storage/keys.rs new file mode 100644 index 0000000000..fa4875bb77 --- /dev/null +++ b/core/src/ledger/pgf/storage/keys.rs @@ -0,0 +1,67 @@ +use namada_macros::StorageKeys; + +use crate::ledger::pgf::ADDRESS; +use crate::types::address::Address; +use crate::types::storage::{DbKeySeg, Key, KeySeg}; + +/// Storage keys for pgf internal address. +#[derive(StorageKeys)] +struct Keys { + stewards: &'static str, + payments: &'static str, + pgf_inflation_rate: &'static str, + steward_inflation_rate: &'static str, +} + +/// Check if key is inside governance address space +pub fn is_pgf_key(key: &Key) -> bool { + matches!(&key.segments[0], DbKeySeg::AddressSeg(addr) if addr == &ADDRESS) +} + +/// Check if key is a steward key +pub fn is_stewards_key(key: &Key) -> bool { + matches!(&key.segments[..], [DbKeySeg::AddressSeg(addr), DbKeySeg::StringSeg(prefix)] if addr == &ADDRESS && prefix == Keys::VALUES.stewards) +} + +/// Check if key is a payments key +pub fn is_payments_key(key: &Key) -> bool { + matches!(&key.segments[..], [DbKeySeg::AddressSeg(addr), DbKeySeg::StringSeg(prefix)] if addr == &ADDRESS && prefix == Keys::VALUES.payments) +} + +/// Check if key is a pgf inflation rate key +pub fn is_pgf_inflation_rate_key(key: &Key) -> bool { + matches!(&key.segments[..], [DbKeySeg::AddressSeg(addr), DbKeySeg::StringSeg(prefix)] if addr == &ADDRESS && prefix == Keys::VALUES.pgf_inflation_rate) +} + +/// Check if key is a steward inflation rate key +pub fn is_steward_inflation_rate_key(key: &Key) -> bool { + matches!(&key.segments[..], [DbKeySeg::AddressSeg(addr), DbKeySeg::StringSeg(prefix)] if addr == &ADDRESS && prefix == Keys::VALUES.steward_inflation_rate) +} + +/// Get key for stewards key +pub fn get_stewards_key() -> Key { + Key::from(ADDRESS.to_db_key()) + .push(&Keys::VALUES.stewards.to_owned()) + .expect("Cannot obtain a storage key") +} + +/// Get key for payments key +pub fn get_payments_key() -> Key { + Key::from(ADDRESS.to_db_key()) + .push(&Keys::VALUES.payments.to_owned()) + .expect("Cannot obtain a storage key") +} + +/// Get key for inflation rate key +pub fn get_pgf_inflation_rate_key() -> Key { + Key::from(ADDRESS.to_db_key()) + .push(&Keys::VALUES.pgf_inflation_rate.to_owned()) + .expect("Cannot obtain a storage key") +} + +/// Get key for inflation rate key +pub fn get_steward_inflation_rate_key() -> Key { + Key::from(ADDRESS.to_db_key()) + .push(&Keys::VALUES.steward_inflation_rate.to_owned()) + .expect("Cannot obtain a storage key") +} diff --git a/core/src/ledger/pgf/storage/mod.rs b/core/src/ledger/pgf/storage/mod.rs new file mode 100644 index 0000000000..fb9d6f8896 --- /dev/null +++ b/core/src/ledger/pgf/storage/mod.rs @@ -0,0 +1,2 @@ +/// Pgf storage keys +pub mod keys; diff --git a/core/src/ledger/slash_fund/storage.rs b/core/src/ledger/slash_fund/storage.rs deleted file mode 100644 index 9c437da591..0000000000 --- a/core/src/ledger/slash_fund/storage.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! Slash fund storage - -use crate::types::storage::{DbKeySeg, Key}; - -/// Check if a key is a slash fund key -pub fn is_slash_fund_key(key: &Key) -> bool { - matches!(&key.segments[0], DbKeySeg::AddressSeg(addr) if addr == &super::ADDRESS) -} diff --git a/core/src/ledger/storage/mod.rs b/core/src/ledger/storage/mod.rs index 6509c02d34..94669a34f4 100644 --- a/core/src/ledger/storage/mod.rs +++ b/core/src/ledger/storage/mod.rs @@ -1225,6 +1225,7 @@ mod tests { tx_whitelist: vec![], implicit_vp_code_hash: Hash::zero(), epochs_per_year: 100, + max_signatures_per_transaction: 15, pos_gain_p: Dec::new(1,1).expect("Cannot fail"), pos_gain_d: Dec::new(1,1).expect("Cannot fail"), staked_ratio: Dec::new(1,1).expect("Cannot fail"), diff --git a/core/src/ledger/storage_api/account.rs b/core/src/ledger/storage_api/account.rs new file mode 100644 index 0000000000..4896de635f --- /dev/null +++ b/core/src/ledger/storage_api/account.rs @@ -0,0 +1,106 @@ +//! Cryptographic signature keys storage API + +use super::*; +use crate::types::account::AccountPublicKeysMap; +use crate::types::address::Address; +use crate::types::key::*; +use crate::types::storage::Key; + +/// Init the subspace of a new account +pub fn init_account_storage( + storage: &mut S, + owner: &Address, + public_keys: &[common::PublicKey], + threshold: u8, +) -> Result<()> +where + S: StorageWrite + StorageRead, +{ + for (index, public_key) in public_keys.iter().enumerate() { + let index = index as u8; + pks_handle(owner).insert(storage, index, public_key.clone())?; + } + let threshold_key = threshold_key(owner); + storage.write(&threshold_key, threshold) +} + +/// Get the threshold associated with an account +pub fn threshold(storage: &S, owner: &Address) -> Result> +where + S: StorageRead, +{ + let threshold_key = threshold_key(owner); + storage.read(&threshold_key) +} + +/// Get the public keys associated with an account +pub fn public_keys( + storage: &S, + owner: &Address, +) -> Result> +where + S: StorageRead, +{ + let public_keys = pks_handle(owner) + .iter(storage)? + .filter_map(|data| match data { + Ok((_index, public_key)) => Some(public_key), + Err(_) => None, + }) + .collect::>(); + + Ok(public_keys) +} + +/// Get the public key index map associated with an account +pub fn public_keys_index_map( + storage: &S, + owner: &Address, +) -> Result +where + S: StorageRead, +{ + let public_keys = public_keys(storage, owner)?; + + Ok(AccountPublicKeysMap::from_iter(public_keys)) +} + +/// Check if an account exists in storage +pub fn exists(storage: &S, owner: &Address) -> Result +where + S: StorageRead, +{ + 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 +pub fn set_public_key_at( + storage: &mut S, + owner: &Address, + public_key: &common::PublicKey, + index: u8, +) -> Result<()> +where + S: StorageWrite + StorageRead, +{ + pks_handle(owner).insert(storage, index, public_key.clone())?; + Ok(()) +} + +/// Clear the public keys account subtorage space +pub fn clear_public_keys(storage: &mut S, owner: &Address) -> Result<()> +where + S: StorageWrite + StorageRead, +{ + let total_pks = pks_handle(owner).len(storage)?; + for index in 0..total_pks as u8 { + pks_handle(owner).remove(storage, &index)?; + } + Ok(()) +} diff --git a/core/src/ledger/storage_api/governance.rs b/core/src/ledger/storage_api/governance.rs index c2316bffa7..1d4d3f767e 100644 --- a/core/src/ledger/storage_api/governance.rs +++ b/core/src/ledger/storage_api/governance.rs @@ -1,12 +1,25 @@ //! Governance +use std::collections::BTreeMap; + +use borsh::BorshDeserialize; + use super::token; -use crate::ledger::governance::{storage, ADDRESS as governance_address}; +use crate::ledger::governance::storage::keys as governance_keys; +use crate::ledger::governance::storage::proposal::{ + ProposalType, StorageProposal, +}; +use crate::ledger::governance::storage::vote::StorageProposalVote; +use crate::ledger::governance::utils::Vote; +use crate::ledger::governance::ADDRESS as governance_address; use crate::ledger::storage_api::{self, StorageRead, StorageWrite}; +use crate::types::address::Address; +use crate::types::storage::Epoch; use crate::types::transaction::governance::{ - InitProposalData, ProposalType, VoteProposalData, + InitProposalData, VoteProposalData, }; +/// A proposal creation transaction. /// A proposal creation transaction. pub fn init_proposal( storage: &mut S, @@ -17,25 +30,26 @@ pub fn init_proposal( where S: StorageRead + StorageWrite, { - let counter_key = storage::get_counter_key(); + let counter_key = governance_keys::get_counter_key(); let proposal_id = if let Some(id) = data.id { id } else { storage.read(&counter_key)?.unwrap() }; - let content_key = storage::get_content_key(proposal_id); + let content_key = governance_keys::get_content_key(proposal_id); storage.write_bytes(&content_key, content)?; - let author_key = storage::get_author_key(proposal_id); + let author_key = governance_keys::get_author_key(proposal_id); storage.write(&author_key, data.author.clone())?; - let proposal_type_key = storage::get_proposal_type_key(proposal_id); + let proposal_type_key = governance_keys::get_proposal_type_key(proposal_id); match data.r#type { ProposalType::Default(Some(_)) => { // Remove wasm code and write it under a different subkey storage.write(&proposal_type_key, ProposalType::Default(None))?; - let proposal_code_key = storage::get_proposal_code_key(proposal_id); + let proposal_code_key = + governance_keys::get_proposal_code_key(proposal_id); let proposal_code = code.clone().ok_or( storage_api::Error::new_const("Missing proposal code"), )?; @@ -45,17 +59,19 @@ where } let voting_start_epoch_key = - storage::get_voting_start_epoch_key(proposal_id); + governance_keys::get_voting_start_epoch_key(proposal_id); storage.write(&voting_start_epoch_key, data.voting_start_epoch)?; - let voting_end_epoch_key = storage::get_voting_end_epoch_key(proposal_id); + let voting_end_epoch_key = + governance_keys::get_voting_end_epoch_key(proposal_id); storage.write(&voting_end_epoch_key, data.voting_end_epoch)?; - let grace_epoch_key = storage::get_grace_epoch_key(proposal_id); + let grace_epoch_key = governance_keys::get_grace_epoch_key(proposal_id); storage.write(&grace_epoch_key, data.grace_epoch)?; if let ProposalType::Default(Some(_)) = data.r#type { - let proposal_code_key = storage::get_proposal_code_key(proposal_id); + let proposal_code_key = + governance_keys::get_proposal_code_key(proposal_id); let proposal_code = code.ok_or(storage_api::Error::new_const("Missing proposal code"))?; storage.write_bytes(&proposal_code_key, proposal_code)?; @@ -63,16 +79,19 @@ where storage.write(&counter_key, proposal_id + 1)?; - let min_proposal_funds_key = storage::get_min_proposal_fund_key(); + let min_proposal_funds_key = governance_keys::get_min_proposal_fund_key(); let min_proposal_funds: token::Amount = storage.read(&min_proposal_funds_key)?.unwrap(); - let funds_key = storage::get_funds_key(proposal_id); + let funds_key = governance_keys::get_funds_key(proposal_id); storage.write(&funds_key, min_proposal_funds)?; // this key must always be written for each proposal let committing_proposals_key = - storage::get_committing_proposals_key(proposal_id, data.grace_epoch.0); + governance_keys::get_committing_proposals_key( + proposal_id, + data.grace_epoch.0, + ); storage.write(&committing_proposals_key, ())?; token::transfer( @@ -93,7 +112,7 @@ where S: StorageRead + StorageWrite, { for delegation in data.delegations { - let vote_key = storage::get_vote_proposal_key( + let vote_key = governance_keys::get_vote_proposal_key( data.id, data.voter.clone(), delegation, @@ -102,3 +121,99 @@ where } Ok(()) } + +/// Read a proposal by id from storage +pub fn get_proposal_by_id( + storage: &S, + id: u64, +) -> storage_api::Result> +where + S: StorageRead, +{ + let author_key = governance_keys::get_author_key(id); + let content = governance_keys::get_content_key(id); + let start_epoch_key = governance_keys::get_voting_start_epoch_key(id); + let end_epoch_key = governance_keys::get_voting_end_epoch_key(id); + let grace_epoch_key = governance_keys::get_grace_epoch_key(id); + let proposal_type_key = governance_keys::get_proposal_type_key(id); + + let author: Option
= storage.read(&author_key)?; + let content: Option> = storage.read(&content)?; + let voting_start_epoch: Option = storage.read(&start_epoch_key)?; + let voting_end_epoch: Option = storage.read(&end_epoch_key)?; + let grace_epoch: Option = storage.read(&grace_epoch_key)?; + let proposal_type: Option = + storage.read(&proposal_type_key)?; + + let proposal = proposal_type.map(|proposal_type| StorageProposal { + id, + content: content.unwrap(), + author: author.unwrap(), + r#type: proposal_type, + voting_start_epoch: voting_start_epoch.unwrap(), + voting_end_epoch: voting_end_epoch.unwrap(), + grace_epoch: grace_epoch.unwrap(), + }); + + Ok(proposal) +} + +/// Query all the votes for a proposal_id +pub fn get_proposal_votes( + storage: &S, + proposal_id: u64, +) -> storage_api::Result> +where + S: storage_api::StorageRead, +{ + let vote_prefix_key = + governance_keys::get_proposal_vote_prefix_key(proposal_id); + let vote_iter = storage_api::iter_prefix::( + storage, + &vote_prefix_key, + )?; + + let votes = vote_iter + .filter_map(|vote_result| { + if let Ok((vote_key, vote)) = vote_result { + let voter_address = + governance_keys::get_voter_address(&vote_key); + let delegator_address = + governance_keys::get_vote_delegation_address(&vote_key); + match (voter_address, delegator_address) { + (Some(delegator_address), Some(validator_address)) => { + Some(Vote { + validator: validator_address.to_owned(), + delegator: delegator_address.to_owned(), + data: vote, + }) + } + _ => None, + } + } else { + None + } + }) + .collect::>(); + + Ok(votes) +} + +/// Check if an accepted proposal is being executed +pub fn is_proposal_accepted( + storage: &S, + tx_data: &[u8], +) -> storage_api::Result +where + S: storage_api::StorageRead, +{ + let proposal_id = u64::try_from_slice(tx_data).ok(); + match proposal_id { + Some(id) => { + let proposal_execution_key = + governance_keys::get_proposal_execution_key(id); + storage.has_key(&proposal_execution_key) + } + None => Ok(false), + } +} diff --git a/core/src/ledger/storage_api/key.rs b/core/src/ledger/storage_api/key.rs index 6e3eba64aa..69bdd50720 100644 --- a/core/src/ledger/storage_api/key.rs +++ b/core/src/ledger/storage_api/key.rs @@ -4,23 +4,17 @@ use super::*; use crate::types::address::Address; use crate::types::key::*; -/// Get the public key associated with the given address. Returns `Ok(None)` if -/// not found. -pub fn get(storage: &S, owner: &Address) -> Result> -where - S: StorageRead, -{ - let key = pk_key(owner); - storage.read(&key) -} - /// Reveal a PK of an implicit account - the PK is written into the storage /// of the address derived from the PK. -pub fn reveal_pk(storage: &mut S, pk: &common::PublicKey) -> Result<()> +pub fn reveal_pk( + storage: &mut S, + public_key: &common::PublicKey, +) -> Result<()> where - S: StorageWrite, + S: StorageWrite + StorageRead, { - let addr: Address = pk.into(); - let key = pk_key(&addr); - storage.write(&key, pk) + let owner: Address = public_key.into(); + pks_handle(&owner).insert(storage, 0, public_key.clone())?; + + Ok(()) } diff --git a/core/src/ledger/storage_api/mod.rs b/core/src/ledger/storage_api/mod.rs index 451996d0e5..1108c44e3d 100644 --- a/core/src/ledger/storage_api/mod.rs +++ b/core/src/ledger/storage_api/mod.rs @@ -1,10 +1,12 @@ //! The common storage read trait is implemented in the storage, client RPC, tx //! and VPs (both native and WASM). +pub mod account; pub mod collections; mod error; pub mod governance; pub mod key; +pub mod pgf; pub mod token; pub mod validation; diff --git a/core/src/ledger/storage_api/pgf.rs b/core/src/ledger/storage_api/pgf.rs new file mode 100644 index 0000000000..8dfafee0fb --- /dev/null +++ b/core/src/ledger/storage_api/pgf.rs @@ -0,0 +1,30 @@ +//! Pgf + +use std::collections::BTreeSet; + +use crate::ledger::governance::storage::proposal::PGFTarget; +use crate::ledger::pgf::storage::keys as pgf_keys; +use crate::ledger::storage_api::{self}; +use crate::types::address::Address; + +/// Query the current pgf steward set +pub fn get_stewards(storage: &S) -> storage_api::Result> +where + S: storage_api::StorageRead, +{ + let stewards_key = pgf_keys::get_stewards_key(); + let stewards: Option> = storage.read(&stewards_key)?; + + Ok(stewards.unwrap_or_default()) +} + +/// Query the current pgf continous payments +pub fn get_payments(storage: &S) -> storage_api::Result> +where + S: storage_api::StorageRead, +{ + let payment_key = pgf_keys::get_payments_key(); + let payments: Option> = storage.read(&payment_key)?; + + Ok(payments.unwrap_or_default()) +} diff --git a/core/src/ledger/storage_api/token.rs b/core/src/ledger/storage_api/token.rs index 1985d8325c..95987d6a83 100644 --- a/core/src/ledger/storage_api/token.rs +++ b/core/src/ledger/storage_api/token.rs @@ -134,3 +134,35 @@ where storage.write(&balance_key, new_balance)?; storage.write(&total_supply_key, new_supply) } + +/// Burn an amount of token for a specific address. +pub fn burn( + storage: &mut S, + token: &Address, + source: &Address, + amount: token::Amount, +) -> storage_api::Result<()> +where + S: StorageRead + StorageWrite, +{ + let key = token::balance_key(token, source); + let balance = read_balance(storage, token, source)?; + + let amount_to_burn = match balance.checked_sub(amount) { + Some(new_balance) => { + storage.write(&key, new_balance)?; + amount + } + None => { + storage.write(&key, token::Amount::default())?; + balance + } + }; + + let total_supply = read_total_supply(&*storage, source)?; + let new_total_supply = + total_supply.checked_sub(amount_to_burn).unwrap_or_default(); + + let total_supply_key = token::minted_balance_key(token); + storage.write(&total_supply_key, new_total_supply) +} diff --git a/core/src/proto/mod.rs b/core/src/proto/mod.rs index 27ae37ff69..e8411a41d2 100644 --- a/core/src/proto/mod.rs +++ b/core/src/proto/mod.rs @@ -4,8 +4,9 @@ pub mod generated; mod types; pub use types::{ - Code, Commitment, Data, Dkg, Error, Header, MaspBuilder, Section, Signable, - SignableEthMessage, Signature, Signed, Tx, TxError, + Code, Commitment, Data, Dkg, Error, Header, MaspBuilder, MultiSignature, + Section, Signable, SignableEthMessage, Signature, SignatureIndex, Signed, + Tx, TxError, }; #[cfg(test)] diff --git a/core/src/proto/types.rs b/core/src/proto/types.rs index 610d453654..59c035561e 100644 --- a/core/src/proto/types.rs +++ b/core/src/proto/types.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; -use std::collections::{HashMap, HashSet}; +use std::cmp::Ordering; +use std::collections::{BTreeSet, HashMap, HashSet}; use std::convert::TryFrom; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; @@ -10,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; @@ -22,8 +24,10 @@ use thiserror::Error; use super::generated::types; use crate::ledger::storage::{KeccakHasher, Sha256Hasher, StorageHasher}; +use crate::ledger::testnet_pow; #[cfg(any(feature = "tendermint", feature = "tendermint-abcipp"))] use crate::tendermint_proto::abci::ResponseDeliverTx; +use crate::types::account::AccountPublicKeysMap; use crate::types::address::Address; use crate::types::chain::ChainId; use crate::types::keccak::{keccak_hash, KeccakHash}; @@ -41,7 +45,9 @@ use crate::types::transaction::EllipticCurve; use crate::types::transaction::EncryptionKey; #[cfg(feature = "ferveo-tpke")] use crate::types::transaction::WrapperTxErr; -use crate::types::transaction::{hash_tx, DecryptedTx, TxType, WrapperTx}; +use crate::types::transaction::{ + hash_tx, DecryptedTx, Fee, GasLimit, TxType, WrapperTx, +}; #[derive(Error, Debug)] pub enum Error { @@ -49,6 +55,8 @@ pub enum Error { TxDecodingError(prost::DecodeError), #[error("Error deserializing transaction field bytes: {0}")] TxDeserializingError(std::io::Error), + #[error("Error deserializing transaction")] + OfflineTxDeserializationError, #[error("Error decoding an DkgGossipMessage from bytes: {0}")] DkgDecodingError(prost::DecodeError), #[error("Dkg is empty")] @@ -57,6 +65,12 @@ pub enum Error { NoTimestampError, #[error("Timestamp is invalid: {0}")] InvalidTimestamp(prost_types::TimestampError), + #[error("The section signature is invalid: {0}")] + InvalidSectionSignature(String), + #[error("Couldn't serialize transaction from JSON at {0}")] + InvalidJSONDeserialization(String), + #[error("The wrapper signature is invalid.")] + InvalidWrapperSignature, } pub type Result = std::result::Result; @@ -360,6 +374,164 @@ impl Code { } } +#[derive( + Clone, + Debug, + BorshSerialize, + BorshDeserialize, + BorshSchema, + Serialize, + Deserialize, + Eq, + PartialEq, +)] +pub struct SignatureIndex { + pub signature: common::Signature, + pub index: u8, +} + +impl SignatureIndex { + pub fn from_single_signature(signature: common::Signature) -> Self { + Self { + signature, + index: 0, + } + } + + pub fn to_vec(&self) -> Vec { + vec![self.clone()] + } + + pub fn verify( + &self, + public_key_index_map: &AccountPublicKeysMap, + data: &impl SignableBytes, + ) -> std::result::Result<(), VerifySigError> { + let public_key = + public_key_index_map.get_public_key_from_index(self.index); + if let Some(public_key) = public_key { + common::SigScheme::verify_signature( + &public_key, + data, + &self.signature, + ) + } else { + Err(VerifySigError::MissingData) + } + } + + pub fn serialize(&self) -> String { + let signature_bytes = + self.try_to_vec().expect("Signature should be serializable"); + HEXUPPER.encode(&signature_bytes) + } + + pub fn deserialize(data: &[u8]) -> Result { + if let Ok(hex) = serde_json::from_slice::(data) { + match HEXUPPER.decode(hex.as_bytes()) { + Ok(bytes) => Self::try_from_slice(&bytes) + .map_err(Error::TxDeserializingError), + Err(_) => Err(Error::OfflineTxDeserializationError), + } + } else { + Err(Error::OfflineTxDeserializationError) + } + } +} + +impl Ord for SignatureIndex { + fn cmp(&self, other: &Self) -> Ordering { + self.index.cmp(&other.index) + } +} + +impl PartialOrd for SignatureIndex { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +/// A section representing a multisig over another section +#[derive( + Clone, + Debug, + BorshSerialize, + BorshDeserialize, + BorshSchema, + Serialize, + Deserialize, +)] +pub struct MultiSignature { + /// The hash of the section being signed + pub targets: Vec, + /// The signature over the above hash + pub signatures: BTreeSet, +} + +impl MultiSignature { + /// Sign the given section hash with the given key and return a section + pub fn new( + targets: Vec, + secret_keys: &[common::SecretKey], + public_keys_index_map: &AccountPublicKeysMap, + ) -> Self { + let target = Self { + targets: targets.clone(), + signatures: BTreeSet::new(), + } + .get_hash(); + + let signatures_public_keys_map = + secret_keys.iter().map(|secret_key: &common::SecretKey| { + let signature = common::SigScheme::sign(secret_key, target); + let public_key = secret_key.ref_to(); + (public_key, signature) + }); + + let signatures = signatures_public_keys_map + .filter_map(|(public_key, signature)| { + let public_key_index = public_keys_index_map + .get_index_from_public_key(&public_key); + public_key_index + .map(|index| SignatureIndex { signature, index }) + }) + .collect::>(); + + Self { + targets, + signatures, + } + } + + pub fn total_signatures(&self) -> u8 { + self.signatures.len() as u8 + } + + /// Hash this signature section + pub fn hash<'a>(&self, hasher: &'a mut Sha256) -> &'a mut Sha256 { + hasher.update( + self.try_to_vec() + .expect("unable to serialize multisignature section"), + ); + hasher + } + + /// Get the hash of this section + pub fn get_hash(&self) -> crate::types::hash::Hash { + crate::types::hash::Hash( + self.hash(&mut Sha256::new()).finalize_reset().into(), + ) + } + + pub fn get_raw_hash(&self) -> crate::types::hash::Hash { + Self { + signatures: BTreeSet::new(), + ..self.clone() + } + .get_hash() + } +} + /// A section representing the signature over another section #[derive( Clone, @@ -371,26 +543,19 @@ impl Code { Deserialize, )] pub struct Signature { - /// Additional random data - salt: [u8; 8], /// The hash of the section being signed targets: Vec, - /// The public key to verify the below signature - pub_key: common::PublicKey, /// The signature over the above hashes pub signature: Option, } impl Signature { - /// Sign the given section hash with the given key and return a section pub fn new( targets: Vec, sec_key: &common::SecretKey, ) -> Self { let mut sec = Self { - salt: DateTimeUtc::now().0.timestamp_millis().to_le_bytes(), targets, - pub_key: sec_key.ref_to(), signature: None, }; sec.signature = Some(common::SigScheme::sign(sec_key, sec.get_hash())); @@ -414,11 +579,14 @@ impl Signature { } /// Verify that the signature contained in this section is valid - pub fn verify_signature(&self) -> std::result::Result<(), VerifySigError> { + pub fn verify_signature( + &self, + public_key: &common::PublicKey, + ) -> std::result::Result<(), VerifySigError> { let signature = self.signature.as_ref().ok_or(VerifySigError::MissingData)?; common::SigScheme::verify_signature( - &self.pub_key, + public_key, &Self { signature: None, ..self.clone() @@ -730,6 +898,8 @@ pub enum Section { /// Transaction code. Sending to hardware wallets optional Code(Code), /// A transaction signature. Often produced by hardware wallets + SectionSignature(MultiSignature), + /// A transaction header/protocol signature Signature(Signature), /// Ciphertext obtained by encrypting arbitrary transaction sections Ciphertext(Ciphertext), @@ -759,7 +929,8 @@ impl Section { Self::Data(data) => data.hash(hasher), Self::ExtraData(extra) => extra.hash(hasher), Self::Code(code) => code.hash(hasher), - Self::Signature(sig) => sig.hash(hasher), + Self::Signature(signature) => signature.hash(hasher), + Self::SectionSignature(signatures) => signatures.hash(hasher), Self::Ciphertext(ct) => ct.hash(hasher), Self::MaspBuilder(mb) => mb.hash(hasher), Self::MaspTx(tx) => { @@ -831,6 +1002,15 @@ impl Section { } } + /// Extract the section signature from this section if possible + pub fn section_signature(&self) -> Option { + if let Self::SectionSignature(data) = self { + Some(data.clone()) + } else { + None + } + } + /// Extract the ciphertext from this section if possible pub fn ciphertext(&self) -> Option { if let Self::Ciphertext(data) = self { @@ -978,15 +1158,57 @@ impl TryFrom<&[u8]> for Tx { } } +impl Default for Tx { + fn default() -> Self { + Self { + header: Header::new(TxType::Raw), + sections: vec![], + } + } +} + impl Tx { + /// Initialize a new transaction builder + pub fn new(chain_id: ChainId, expiration: Option) -> Self { + Tx { + sections: vec![], + header: Header { + chain_id, + expiration, + ..Header::new(TxType::Raw) + }, + } + } + /// Create a transaction of the given type - pub fn new(header: TxType) -> Self { + pub fn from_type(header: TxType) -> Self { Tx { header: Header::new(header), sections: vec![], } } + /// Serialize 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) + } + + // Deserialize from hex encoding + pub fn deserialize(data: &[u8]) -> Result { + if let Ok(hex) = serde_json::from_slice::(data) { + match HEXUPPER.decode(hex.as_bytes()) { + Ok(bytes) => Tx::try_from_slice(&bytes) + .map_err(Error::TxDeserializingError), + Err(_) => Err(Error::OfflineTxDeserializationError), + } + } else { + Err(Error::OfflineTxDeserializationError) + } + } + /// Get the transaction header pub fn header(&self) -> Header { self.header.clone() @@ -1105,36 +1327,113 @@ impl Tx { bytes } + /// Get the inner section hashes + pub fn inner_section_targets(&self) -> Vec { + self.sections + .iter() + .filter_map(|section| match section { + Section::Data(_) | Section::Code(_) => Some(section.get_hash()), + _ => None, + }) + .collect() + } + + /// Verify that the section with the given hash has been signed by the given + /// public key + pub fn verify_section_signatures( + &self, + hashes: &[crate::types::hash::Hash], + public_keys_index_map: AccountPublicKeysMap, + threshold: u8, + max_signatures: Option, + ) -> std::result::Result<(), Error> { + let max_signatures = max_signatures.unwrap_or(u8::MAX); + let mut valid_signatures = 0; + + for section in &self.sections { + if let Section::SectionSignature(signatures) = section { + if !hashes.iter().all(|x| { + signatures.targets.contains(x) || section.get_hash() == *x + }) { + return Err(Error::InvalidSectionSignature( + "missing target hash.".to_string(), + )); + } + + for target in &signatures.targets { + if self.get_section(target).is_none() { + return Err(Error::InvalidSectionSignature( + "Missing target section.".to_string(), + )); + } + } + + if signatures.total_signatures() > max_signatures { + return Err(Error::InvalidSectionSignature( + "too many signatures.".to_string(), + )); + } + + if signatures.total_signatures() < threshold { + return Err(Error::InvalidSectionSignature( + "too few signatures.".to_string(), + )); + } + + for signature_index in &signatures.signatures { + let is_valid_signature = signature_index + .verify( + &public_keys_index_map, + &signatures.get_raw_hash(), + ) + .is_ok(); + if is_valid_signature { + valid_signatures += 1; + } + if valid_signatures >= threshold { + return Ok(()); + } + } + } + } + Err(Error::InvalidSectionSignature( + "invalid signatures.".to_string(), + )) + } + /// Verify that the sections with the given hashes have been signed together /// by the given public key. I.e. this function looks for one signature that /// covers over the given slice of hashes. pub fn verify_signature( &self, - pk: &common::PublicKey, + public_key: &common::PublicKey, hashes: &[crate::types::hash::Hash], - ) -> std::result::Result<&Signature, VerifySigError> { + ) -> Result<&Signature> { for section in &self.sections { - if let Section::Signature(sig_sec) = section { - // Check that the signer is matched and that the hashes being + if let Section::Signature(signature) = section { + // Check that the hashes being // checked are a subset of those in this section - if sig_sec.pub_key == *pk - && hashes.iter().all(|x| { - sig_sec.targets.contains(x) || section.get_hash() == *x - }) - { + if hashes.iter().all(|x| { + signature.targets.contains(x) || section.get_hash() == *x + }) { // Ensure that all the sections the signature signs over are // present - for target in &sig_sec.targets { + for target in &signature.targets { if self.get_section(target).is_none() { - return Err(VerifySigError::MissingData); + return Err(Error::InvalidSectionSignature( + "Target section is missing.".to_string(), + )); } } // Finally verify that the signature itself is valid - return sig_sec.verify_signature().map(|_| sig_sec); + return signature + .verify_signature(public_key) + .map(|_| signature) + .map_err(|_| Error::InvalidWrapperSignature); } } } - Err(VerifySigError::MissingData) + Err(Error::InvalidWrapperSignature) } /// Validate any and all ciphertexts stored in this transaction @@ -1153,6 +1452,16 @@ impl Tx { valid } + pub fn compute_section_signature( + &self, + secret_keys: &[common::SecretKey], + public_keys_index_map: &AccountPublicKeysMap, + ) -> BTreeSet { + let targets = [*self.data_sechash(), *self.code_sechash()].to_vec(); + MultiSignature::new(targets, secret_keys, public_keys_index_map) + .signatures + } + /// Decrypt any and all ciphertexts stored in this transaction use the /// given decryption key #[cfg(feature = "ferveo-tpke")] @@ -1180,7 +1489,7 @@ impl Tx { /// Encrypt all sections in this transaction other than the header and /// signatures over it #[cfg(feature = "ferveo-tpke")] - pub fn encrypt(&mut self, pubkey: &EncryptionKey) { + pub fn encrypt(&mut self, pubkey: &EncryptionKey) -> &mut Self { let header_hash = self.header_hash(); let mut plaintexts = vec![]; // Iterate backwrds to sidestep the effects of deletion on indexing @@ -1195,6 +1504,7 @@ impl Tx { // Encrypt all eligible sections in one go self.sections .push(Section::Ciphertext(Ciphertext::new(plaintexts, pubkey))); + self } /// Determines the type of the input Tx @@ -1280,6 +1590,139 @@ impl Tx { } filtered } + + /// Add an extra section to the tx builder by hash + pub fn add_extra_section_from_hash( + &mut self, + hash: crate::types::hash::Hash, + ) -> crate::types::hash::Hash { + let sechash = self + .add_section(Section::ExtraData(Code::from_hash(hash))) + .get_hash(); + sechash + } + + /// Add an extra section to the tx builder by code + pub fn add_extra_section( + &mut self, + code: Vec, + ) -> (&mut Self, crate::types::hash::Hash) { + let sechash = self + .add_section(Section::ExtraData(Code::new(code))) + .get_hash(); + (self, sechash) + } + + /// Add a masp tx section to the tx builder + pub fn add_masp_tx_section( + &mut self, + tx: Transaction, + ) -> (&mut Self, crate::types::hash::Hash) { + let sechash = self.add_section(Section::MaspTx(tx)).get_hash(); + (self, sechash) + } + + /// Add a masp builder section to the tx builder + pub fn add_masp_builder(&mut self, builder: MaspBuilder) -> &mut Self { + let _sec = self.add_section(Section::MaspBuilder(builder)); + self + } + + /// Add wasm code to the tx builder from hash + pub fn add_code_from_hash( + &mut self, + code_hash: crate::types::hash::Hash, + ) -> &mut Self { + self.set_code(Code::from_hash(code_hash)); + self + } + + /// Add wasm code to the tx builder + pub fn add_code(&mut self, code: Vec) -> &mut Self { + self.set_code(Code::new(code)); + self + } + + /// Add wasm data to the tx builder + pub fn add_data(&mut self, data: impl BorshSerialize) -> &mut Self { + let bytes = data.try_to_vec().expect("Encoding tx data shouldn't fail"); + self.set_data(Data::new(bytes)); + self + } + + /// Add wasm data already serialized to the tx builder + pub fn add_serialized_data(&mut self, bytes: Vec) -> &mut Self { + self.set_data(Data::new(bytes)); + self + } + + /// Add wrapper tx to the tx builder + pub fn add_wrapper( + &mut self, + fee: Fee, + gas_payer: common::PublicKey, + epoch: Epoch, + gas_limit: GasLimit, + #[cfg(not(feature = "mainnet"))] requires_pow: Option< + testnet_pow::Solution, + >, + ) -> &mut Self { + self.header.tx_type = TxType::Wrapper(Box::new(WrapperTx::new( + fee, + gas_payer, + epoch, + gas_limit, + #[cfg(not(feature = "mainnet"))] + requires_pow, + ))); + self + } + + /// Add fee payer keypair to the tx builder + pub fn sign_wrapper(&mut self, keypair: common::SecretKey) -> &mut Self { + self.protocol_filter(); + self.add_section(Section::Signature(Signature::new( + self.sechashes(), + &keypair, + ))); + self + } + + /// Add signing keys to the tx builder + pub fn sign_raw( + &mut self, + keypairs: Vec, + account_public_keys_map: AccountPublicKeysMap, + ) -> &mut Self { + self.protocol_filter(); + let hashes = self + .sections + .iter() + .filter_map(|section| match section { + Section::Data(_) | Section::Code(_) => Some(section.get_hash()), + _ => None, + }) + .collect(); + self.add_section(Section::SectionSignature(MultiSignature::new( + hashes, + &keypairs, + &account_public_keys_map, + ))); + self + } + + /// Add signature + pub fn add_signatures( + &mut self, + signatures: BTreeSet, + ) -> &mut Self { + self.protocol_filter(); + self.add_section(Section::SectionSignature(MultiSignature { + targets: self.inner_section_targets(), + signatures, + })); + self + } } #[cfg(any(feature = "tendermint", feature = "tendermint-abcipp"))] diff --git a/core/src/types/account.rs b/core/src/types/account.rs new file mode 100644 index 0000000000..d66876ba37 --- /dev/null +++ b/core/src/types/account.rs @@ -0,0 +1,92 @@ +//! Helper structures to manage accounts + +use std::collections::HashMap; + +use borsh::{BorshDeserialize, BorshSerialize}; +use serde::{Deserialize, Serialize}; + +use super::address::Address; +use super::key::common; + +#[derive( + Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, +)] +/// Account data +pub struct Account { + /// The map between indexes and public keys for an account + pub public_keys_map: AccountPublicKeysMap, + /// The account signature threshold + pub threshold: u8, + /// The address corresponding to the account owner + pub address: Address, +} + +impl Account { + /// Retrive a public key from the index + pub fn get_public_key_from_index( + &self, + index: u8, + ) -> Option { + self.public_keys_map.get_public_key_from_index(index) + } + + /// Retrive the index of a public key + pub fn get_index_from_public_key( + &self, + public_key: &common::PublicKey, + ) -> Option { + self.public_keys_map.get_index_from_public_key(public_key) + } +} + +#[derive( + Debug, + Clone, + BorshSerialize, + BorshDeserialize, + Serialize, + Deserialize, + Default, +)] +/// Holds the public key map data as a bimap for efficient quering +pub struct AccountPublicKeysMap { + /// Hashmap from public key to index + pub pk_to_idx: HashMap, + /// Hashmap from index key to public key + pub idx_to_pk: HashMap, +} + +impl FromIterator for AccountPublicKeysMap { + fn from_iter>(iter: T) -> Self { + let mut pk_to_idx = HashMap::new(); + let mut idx_to_pk = HashMap::new(); + + for (index, public_key) in iter.into_iter().enumerate() { + pk_to_idx.insert(public_key.to_owned(), index as u8); + idx_to_pk.insert(index as u8, public_key.to_owned()); + } + + Self { + pk_to_idx, + idx_to_pk, + } + } +} + +impl AccountPublicKeysMap { + /// Retrive a public key from the index + pub fn get_public_key_from_index( + &self, + index: u8, + ) -> Option { + self.idx_to_pk.get(&index).cloned() + } + + /// Retrive the index of a public key + pub fn get_index_from_public_key( + &self, + public_key: &common::PublicKey, + ) -> Option { + self.pk_to_idx.get(public_key).cloned() + } +} diff --git a/core/src/types/address.rs b/core/src/types/address.rs index 1a6611a2f5..d587d20280 100644 --- a/core/src/types/address.rs +++ b/core/src/types/address.rs @@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use thiserror::Error; -use crate::ibc::signer::Signer; +use crate::ibc::Signer; use crate::types::ethereum_events::EthAddress; use crate::types::key; use crate::types::key::PublicKeyHash; @@ -75,8 +75,6 @@ mod internal { "ano::Protocol Parameters "; pub const GOVERNANCE: &str = "ano::Governance "; - pub const SLASH_FUND: &str = - "ano::Slash Fund "; pub const IBC: &str = "ibc::Inter-Blockchain Communication "; pub const ETH_BRIDGE: &str = @@ -87,6 +85,8 @@ mod internal { "ano::Replay Protection "; pub const MULTITOKEN: &str = "ano::Multitoken "; + pub const PGF: &str = + "ano::Pgf "; } /// Fixed-length address strings prefix for established addresses. @@ -219,9 +219,6 @@ impl Address { InternalAddress::Governance => { internal::GOVERNANCE.to_string() } - InternalAddress::SlashFund => { - internal::SLASH_FUND.to_string() - } InternalAddress::Ibc => internal::IBC.to_string(), InternalAddress::IbcToken(hash) => { format!("{}::{}", PREFIX_IBC, hash) @@ -243,6 +240,7 @@ impl Address { InternalAddress::Multitoken => { internal::MULTITOKEN.to_string() } + InternalAddress::Pgf => internal::PGF.to_string(), }; debug_assert_eq!(string.len(), FIXED_LEN_STRING_BYTES); string @@ -304,9 +302,6 @@ impl Address { internal::GOVERNANCE => { Ok(Address::Internal(InternalAddress::Governance)) } - internal::SLASH_FUND => { - Ok(Address::Internal(InternalAddress::SlashFund)) - } internal::ETH_BRIDGE => { Ok(Address::Internal(InternalAddress::EthBridge)) } @@ -319,6 +314,7 @@ impl Address { internal::MULTITOKEN => { Ok(Address::Internal(InternalAddress::Multitoken)) } + internal::PGF => Ok(Address::Internal(InternalAddress::Pgf)), _ => Err(Error::new( ErrorKind::InvalidData, "Invalid internal address", @@ -541,8 +537,6 @@ pub enum InternalAddress { IbcToken(String), /// Governance address Governance, - /// SlashFund address for governance - SlashFund, /// Bridge to Ethereum EthBridge, /// The pool of transactions to be relayed to Ethereum @@ -553,6 +547,8 @@ pub enum InternalAddress { ReplayProtection, /// Multitoken Multitoken, + /// Pgf + Pgf, } impl Display for InternalAddress { @@ -565,7 +561,6 @@ impl Display for InternalAddress { Self::PosSlashPool => "PosSlashPool".to_string(), Self::Parameters => "Parameters".to_string(), Self::Governance => "Governance".to_string(), - Self::SlashFund => "SlashFund".to_string(), Self::Ibc => "IBC".to_string(), Self::IbcToken(hash) => format!("IbcToken: {}", hash), Self::EthBridge => "EthBridge".to_string(), @@ -573,6 +568,7 @@ impl Display for InternalAddress { Self::Erc20(eth_addr) => format!("Erc20: {}", eth_addr), Self::ReplayProtection => "ReplayProtection".to_string(), Self::Multitoken => "Multitoken".to_string(), + Self::Pgf => "PublicGoodFundings".to_string(), } ) } @@ -859,7 +855,6 @@ pub mod testing { InternalAddress::PoS => {} InternalAddress::PosSlashPool => {} InternalAddress::Governance => {} - InternalAddress::SlashFund => {} InternalAddress::Parameters => {} InternalAddress::Ibc => {} InternalAddress::IbcToken(_) => {} @@ -867,6 +862,7 @@ pub mod testing { InternalAddress::EthBridgePool => {} InternalAddress::Erc20(_) => {} InternalAddress::ReplayProtection => {} + InternalAddress::Pgf => {} InternalAddress::Multitoken => {} /* Add new addresses in the * `prop_oneof` below. */ }; @@ -877,12 +873,12 @@ pub mod testing { Just(InternalAddress::Parameters), arb_ibc_token(), Just(InternalAddress::Governance), - Just(InternalAddress::SlashFund), Just(InternalAddress::EthBridge), Just(InternalAddress::EthBridgePool), Just(arb_erc20()), Just(InternalAddress::ReplayProtection), Just(InternalAddress::Multitoken), + Just(InternalAddress::Pgf), ] } diff --git a/core/src/types/dec.rs b/core/src/types/dec.rs index fdff5dc620..48589a1c32 100644 --- a/core/src/types/dec.rs +++ b/core/src/types/dec.rs @@ -410,7 +410,8 @@ impl Display for Dec { str_pre.push_str(string.as_str()); string = str_pre; }; - let stripped_string = string.trim_end_matches(['.', '0']); + let stripped_string = string.trim_end_matches('0'); + let stripped_string = stripped_string.trim_end_matches('.'); if stripped_string.is_empty() { f.write_str("0") } else if is_neg { @@ -620,4 +621,11 @@ mod test_dec { let larger = Dec::from_str("32418116583.390243854642").unwrap(); assert!(smaller < larger); } + + #[test] + fn test_dec_display() { + let num = Dec::from_str("14000.0000").unwrap(); + let s = format!("{}", num); + assert_eq!(s, String::from("14000")); + } } diff --git a/core/src/types/governance.rs b/core/src/types/governance.rs deleted file mode 100644 index d3450dccd1..0000000000 --- a/core/src/types/governance.rs +++ /dev/null @@ -1,384 +0,0 @@ -//! Files defyining the types used in governance. - -use std::collections::{BTreeMap, HashSet}; -use std::fmt::{self, Display}; - -use borsh::{BorshDeserialize, BorshSerialize}; -use serde::{Deserialize, Serialize}; -use thiserror::Error; - -use crate::types::address::Address; -use crate::types::hash::Hash; -use crate::types::key::common::{self, Signature}; -use crate::types::key::SigScheme; -use crate::types::storage::Epoch; -use crate::types::token::{ - Amount, DenominatedAmount, NATIVE_MAX_DECIMAL_PLACES, -}; -use crate::types::uint::Uint; - -/// Type alias for vote power -pub type VotePower = Uint; - -/// A PGF cocuncil composed of the address and spending cap -pub type Council = (Address, Amount); - -/// The type of a governance vote with the optional associated Memo -#[derive( - Debug, - Clone, - PartialEq, - BorshSerialize, - BorshDeserialize, - Serialize, - Deserialize, - Eq, -)] -pub enum VoteType { - /// A default vote without Memo - Default, - /// A vote for the PGF council - PGFCouncil(HashSet), - /// A vote for ETH bridge carrying the signature over the proposed message - ETHBridge(Signature), -} - -#[derive( - Debug, - Clone, - PartialEq, - BorshSerialize, - BorshDeserialize, - Serialize, - Deserialize, - Eq, -)] -/// The vote for a proposal -pub enum ProposalVote { - /// Yes - Yay(VoteType), - /// No - Nay, -} - -impl ProposalVote { - /// Check if a vote is yay - pub fn is_yay(&self) -> bool { - matches!(self, ProposalVote::Yay(_)) - } - - /// Check if vote is of type default - pub fn is_default_vote(&self) -> bool { - matches!( - self, - ProposalVote::Yay(VoteType::Default) | ProposalVote::Nay - ) - } -} - -impl Display for ProposalVote { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - ProposalVote::Yay(vote_type) => match vote_type { - VoteType::Default => write!(f, "yay"), - VoteType::PGFCouncil(councils) => { - writeln!(f, "yay with councils:")?; - for (address, spending_cap) in councils { - writeln!( - f, - "Council: {}, spending cap: {}", - address, - spending_cap.to_string_native() - )? - } - - Ok(()) - } - VoteType::ETHBridge(sig) => { - write!(f, "yay with signature: {:#?}", sig) - } - }, - - ProposalVote::Nay => write!(f, "nay"), - } - } -} - -#[allow(missing_docs)] -#[derive(Debug, Error)] -pub enum ProposalVoteParseError { - #[error("Invalid vote. Vote shall be yay or nay.")] - InvalidVote, -} - -/// The type of the tally -#[derive(Clone, Debug)] -pub enum Tally { - /// Default proposal - Default, - /// PGF proposal - PGFCouncil(Council), - /// ETH Bridge proposal - ETHBridge, -} - -/// The result of a proposal -#[derive(Clone, Debug)] -pub enum TallyResult { - /// Proposal was accepted with the associated value - Passed(Tally), - /// Proposal was rejected - Rejected, -} - -/// The result with votes of a proposal -pub struct ProposalResult { - /// The result of a proposal - pub result: TallyResult, - /// The total voting power during the proposal tally - pub total_voting_power: VotePower, - /// The total voting power from yay votes - pub total_yay_power: VotePower, - /// The total voting power from nay votes (unused at the moment) - pub total_nay_power: VotePower, -} - -impl Display for ProposalResult { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let percentage = DenominatedAmount { - amount: Amount::from_uint( - self.total_yay_power - .fixed_precision_div(&self.total_voting_power, 4) - .unwrap_or_default(), - 0, - ) - .unwrap(), - denom: 2.into(), - }; - - write!( - f, - "{} with {} yay votes over {} ({}%)", - self.result, - DenominatedAmount { - amount: Amount::from_uint(self.total_yay_power, 0).unwrap(), - denom: NATIVE_MAX_DECIMAL_PLACES.into() - }, - DenominatedAmount { - amount: Amount::from_uint(self.total_voting_power, 0).unwrap(), - denom: NATIVE_MAX_DECIMAL_PLACES.into() - }, - percentage - ) - } -} - -impl Display for TallyResult { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - TallyResult::Passed(vote) => match vote { - Tally::Default | Tally::ETHBridge => write!(f, "passed"), - Tally::PGFCouncil((council, cap)) => write!( - f, - "passed with PGF council address: {}, spending cap: {}", - council, - cap.to_string_native() - ), - }, - TallyResult::Rejected => write!(f, "rejected"), - } - } -} - -/// The type of a governance proposal -#[derive( - Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, -)] -pub enum ProposalType { - /// A default proposal with the optional path to wasm code - Default(Option), - /// A PGF council proposal - PGFCouncil, - /// An ETH bridge proposal - ETHBridge, -} - -#[derive( - Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, -)] -/// The proposal structure -pub struct Proposal { - /// The proposal id - pub id: Option, - /// The proposal content - pub content: BTreeMap, - /// The proposal author address - pub author: Address, - /// The proposal type - pub r#type: ProposalType, - /// The epoch from which voting is allowed - pub voting_start_epoch: Epoch, - /// The epoch from which voting is stopped - pub voting_end_epoch: Epoch, - /// The epoch from which this changes are executed - pub grace_epoch: Epoch, -} - -impl Display for Proposal { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "id: {:?}, author: {:?}", self.id, self.author) - } -} - -#[allow(missing_docs)] -#[derive(Debug, Error)] -pub enum ProposalError { - #[error("Invalid proposal data.")] - InvalidProposalData, -} - -#[derive( - Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, -)] -/// The offline proposal structure -pub struct OfflineProposal { - /// The proposal content - pub content: BTreeMap, - /// The proposal author address - pub author: Address, - /// The epoch from which this changes are executed - pub tally_epoch: Epoch, - /// The signature over proposal data - pub signature: Signature, - /// The address corresponding to the signature pk - pub address: Address, -} - -impl OfflineProposal { - /// Create an offline proposal with a signature - pub fn new( - proposal: Proposal, - address: Address, - signing_key: &common::SecretKey, - ) -> Self { - let content_serialized = serde_json::to_vec(&proposal.content) - .expect("Conversion to bytes shouldn't fail."); - let author_serialized = serde_json::to_vec(&proposal.author) - .expect("Conversion to bytes shouldn't fail."); - let tally_epoch_serialized = serde_json::to_vec(&proposal.grace_epoch) - .expect("Conversion to bytes shouldn't fail."); - let proposal_serialized = &[ - content_serialized, - author_serialized, - tally_epoch_serialized, - ] - .concat(); - let proposal_data_hash = Hash::sha256(proposal_serialized); - let signature = - common::SigScheme::sign(signing_key, proposal_data_hash); - Self { - content: proposal.content, - author: proposal.author, - tally_epoch: proposal.grace_epoch, - signature, - address, - } - } - - /// Check whether the signature is valid or not - pub fn check_signature(&self, public_key: &common::PublicKey) -> bool { - let proposal_data_hash = self.compute_hash(); - common::SigScheme::verify_signature( - public_key, - &proposal_data_hash, - &self.signature, - ) - .is_ok() - } - - /// Compute the hash of the proposal - pub fn compute_hash(&self) -> Hash { - let content_serialized = serde_json::to_vec(&self.content) - .expect("Conversion to bytes shouldn't fail."); - let author_serialized = serde_json::to_vec(&self.author) - .expect("Conversion to bytes shouldn't fail."); - let tally_epoch_serialized = serde_json::to_vec(&self.tally_epoch) - .expect("Conversion to bytes shouldn't fail."); - let proposal_serialized = &[ - content_serialized, - author_serialized, - tally_epoch_serialized, - ] - .concat(); - Hash::sha256(proposal_serialized) - } -} - -#[derive( - Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, -)] -/// The offline proposal structure -pub struct OfflineVote { - /// The proposal data hash - pub proposal_hash: Hash, - /// The proposal vote - pub vote: ProposalVote, - /// The signature over proposal data - pub signature: Signature, - /// The address corresponding to the signature pk - pub address: Address, -} - -impl OfflineVote { - /// Create an offline vote for a proposal - pub fn new( - proposal: &OfflineProposal, - vote: ProposalVote, - address: Address, - signing_key: &common::SecretKey, - ) -> Self { - let proposal_hash = proposal.compute_hash(); - let proposal_hash_data = proposal_hash - .try_to_vec() - .expect("Conversion to bytes shouldn't fail."); - let proposal_vote_data = vote - .try_to_vec() - .expect("Conversion to bytes shouldn't fail."); - let vote_serialized = - &[proposal_hash_data, proposal_vote_data].concat(); - let signature = common::SigScheme::sign(signing_key, vote_serialized); - Self { - proposal_hash, - vote, - signature, - address, - } - } - - /// compute the hash of a proposal - pub fn compute_hash(&self) -> Hash { - let proposal_hash_data = self - .proposal_hash - .try_to_vec() - .expect("Conversion to bytes shouldn't fail."); - let proposal_vote_data = self - .vote - .try_to_vec() - .expect("Conversion to bytes shouldn't fail."); - let vote_serialized = - &[proposal_hash_data, proposal_vote_data].concat(); - - Hash::sha256(vote_serialized) - } - - /// Check whether the signature is valid or not - pub fn check_signature(&self, public_key: &common::PublicKey) -> bool { - let vote_data_hash = self.compute_hash(); - common::SigScheme::verify_signature( - public_key, - &vote_data_hash, - &self.signature, - ) - .is_ok() - } -} diff --git a/core/src/types/ibc.rs b/core/src/types/ibc.rs index 5e7514aea3..7a412ecb05 100644 --- a/core/src/types/ibc.rs +++ b/core/src/types/ibc.rs @@ -52,7 +52,9 @@ mod ibc_rs_conversion { use thiserror::Error; use super::IbcEvent; - use crate::ibc::events::{Error as IbcEventError, IbcEvent as RawIbcEvent}; + use crate::ibc::core::events::{ + Error as IbcEventError, IbcEvent as RawIbcEvent, + }; use crate::tendermint_proto::abci::Event as AbciEvent; #[allow(missing_docs)] @@ -69,7 +71,7 @@ mod ibc_rs_conversion { type Error = Error; fn try_from(e: RawIbcEvent) -> Result { - let event_type = e.event_type().as_str().to_string(); + let event_type = e.event_type().to_string(); let abci_event = AbciEvent::try_from(e).map_err(Error::IbcEvent)?; let attributes: HashMap<_, _> = abci_event .attributes diff --git a/core/src/types/key/mod.rs b/core/src/types/key/mod.rs index 8c59262f72..685e3464f7 100644 --- a/core/src/types/key/mod.rs +++ b/core/src/types/key/mod.rs @@ -12,6 +12,8 @@ use std::str::FromStr; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use data_encoding::HEXUPPER; +use lazy_map::LazyMap; +use namada_macros::StorageKeys; #[cfg(feature = "rand")] use rand::{CryptoRng, RngCore}; use serde::Serialize; @@ -19,25 +21,45 @@ use sha2::{Digest, Sha256}; use thiserror::Error; use super::address::Address; -use super::storage::{self, DbKeySeg, Key, KeySeg}; +use super::storage::{self, DbKeySeg, Key}; use crate::ledger::storage::{Sha256Hasher, StorageHasher}; +use crate::ledger::storage_api::collections::{lazy_map, LazyCollection}; use crate::types::address; -const PK_STORAGE_KEY: &str = "public_key"; -const PROTOCOL_PK_STORAGE_KEY: &str = "protocol_public_key"; +/// Storage keys for account. +#[derive(StorageKeys)] +struct Keys { + public_keys: &'static str, + threshold: &'static str, + protocol_public_keys: &'static str, +} /// Obtain a storage key for user's public key. -pub fn pk_key(owner: &Address) -> storage::Key { - Key::from(owner.to_db_key()) - .push(&PK_STORAGE_KEY.to_owned()) - .expect("Cannot obtain a storage key") +pub fn pks_key_prefix(owner: &Address) -> storage::Key { + Key { + segments: vec![ + DbKeySeg::AddressSeg(owner.to_owned()), + DbKeySeg::StringSeg(Keys::VALUES.public_keys.to_string()), + ], + } +} + +/// Object that LazyMap handler for the user's public key subspace +pub fn pks_handle(owner: &Address) -> LazyMap { + LazyMap::open(pks_key_prefix(owner)) } /// Check if the given storage key is a public key. If it is, returns the owner. -pub fn is_pk_key(key: &Key) -> Option<&Address> { +pub fn is_pks_key(key: &Key) -> Option<&Address> { match &key.segments[..] { - [DbKeySeg::AddressSeg(owner), DbKeySeg::StringSeg(key)] - if key == PK_STORAGE_KEY => + [ + DbKeySeg::AddressSeg(owner), + DbKeySeg::StringSeg(prefix), + DbKeySeg::StringSeg(data), + DbKeySeg::StringSeg(index), + ] if prefix.as_str() == Keys::VALUES.public_keys + && data.as_str() == lazy_map::DATA_SUBKEY + && index.parse::().is_ok() => { Some(owner) } @@ -45,18 +67,43 @@ pub fn is_pk_key(key: &Key) -> Option<&Address> { } } +/// Check if the given storage key is a threshol key. +pub fn is_threshold_key(key: &Key) -> Option<&Address> { + match &key.segments[..] { + [DbKeySeg::AddressSeg(owner), DbKeySeg::StringSeg(prefix)] + if prefix.as_str() == Keys::VALUES.threshold => + { + Some(owner) + } + _ => None, + } +} + +/// Obtain the storage key for a user threshold +pub fn threshold_key(owner: &Address) -> storage::Key { + Key { + segments: vec![ + DbKeySeg::AddressSeg(owner.to_owned()), + DbKeySeg::StringSeg(Keys::VALUES.threshold.to_string()), + ], + } +} + /// Obtain a storage key for user's protocol public key. pub fn protocol_pk_key(owner: &Address) -> storage::Key { - Key::from(owner.to_db_key()) - .push(&PROTOCOL_PK_STORAGE_KEY.to_owned()) - .expect("Cannot obtain a storage key") + Key { + segments: vec![ + DbKeySeg::AddressSeg(owner.to_owned()), + DbKeySeg::StringSeg(Keys::VALUES.protocol_public_keys.to_string()), + ], + } } /// Check if the given storage key is a public key. If it is, returns the owner. pub fn is_protocol_pk_key(key: &Key) -> Option<&Address> { match &key.segments[..] { [DbKeySeg::AddressSeg(owner), DbKeySeg::StringSeg(key)] - if key == PROTOCOL_PK_STORAGE_KEY => + if key.as_str() == Keys::VALUES.protocol_public_keys => { Some(owner) } diff --git a/core/src/types/mod.rs b/core/src/types/mod.rs index c35b314296..8aee038d9b 100644 --- a/core/src/types/mod.rs +++ b/core/src/types/mod.rs @@ -1,5 +1,6 @@ //! Types definitions. +pub mod account; pub mod address; pub mod chain; pub mod dec; @@ -7,7 +8,6 @@ pub mod eth_abi; pub mod eth_bridge_pool; pub mod ethereum_events; pub mod ethereum_structs; -pub mod governance; pub mod hash; pub mod ibc; pub mod internal; diff --git a/core/src/types/token.rs b/core/src/types/token.rs index bf4e23cbe3..6056495cd1 100644 --- a/core/src/types/token.rs +++ b/core/src/types/token.rs @@ -76,6 +76,11 @@ impl Amount { self.raw = self.raw.checked_sub(amount.raw).unwrap(); } + /// Check if there are enough funds. + pub fn can_spend(&self, amount: &Amount) -> bool { + self.raw >= amount.raw + } + /// Receive a given amount. /// Panics on overflow and when [`uint::MAX_SIGNED_VALUE`] is exceeded. pub fn receive(&mut self, amount: &Amount) { @@ -154,6 +159,20 @@ impl Amount { Self { raw: change.abs() } } + /// Checked division. Returns `None` on underflow. + pub fn checked_div(&self, amount: Amount) -> Option { + self.raw + .checked_div(amount.raw) + .map(|result| Self { raw: result }) + } + + /// Checked division. Returns `None` on overflow. + pub fn checked_mul(&self, amount: Amount) -> Option { + self.raw + .checked_mul(amount.raw) + .map(|result| Self { raw: result }) + } + /// Given a string and a denomination, parse an amount from string. pub fn from_str( string: impl AsRef, diff --git a/core/src/types/transaction/account.rs b/core/src/types/transaction/account.rs new file mode 100644 index 0000000000..f2eaafe7ef --- /dev/null +++ b/core/src/types/transaction/account.rs @@ -0,0 +1,52 @@ +use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; +use serde::{Deserialize, Serialize}; + +use crate::types::address::Address; +use crate::types::hash::Hash; +use crate::types::key::common; + +/// A tx data type to initialize a new established account +#[derive( + Debug, + Clone, + PartialEq, + BorshSerialize, + BorshDeserialize, + BorshSchema, + Serialize, + Deserialize, +)] +pub struct InitAccount { + /// Public keys to be written into the account's storage. This can be used + /// for signature verification of transactions for the newly created + /// account. + pub public_keys: Vec, + /// The VP code hash + pub vp_code_hash: Hash, + /// The account signature threshold + pub threshold: u8, +} + +/// A tx data type to update an account's validity predicate +#[derive( + Debug, + Clone, + PartialEq, + BorshSerialize, + BorshDeserialize, + BorshSchema, + Serialize, + Deserialize, +)] +pub struct UpdateAccount { + /// An address of the account + pub addr: Address, + /// The new VP code hash + pub vp_code_hash: Option, + /// Public keys to be written into the account's storage. This can be used + /// for signature verification of transactions for the newly created + /// account. + pub public_keys: Vec, + /// The account signature threshold + pub threshold: Option, +} diff --git a/core/src/types/transaction/governance.rs b/core/src/types/transaction/governance.rs index bfc17eeaef..0d653c44cf 100644 --- a/core/src/types/transaction/governance.rs +++ b/core/src/types/transaction/governance.rs @@ -1,86 +1,25 @@ -use std::fmt::Display; +use std::collections::HashSet; use borsh::{BorshDeserialize, BorshSerialize}; use serde::{Deserialize, Serialize}; +use thiserror::Error; -use crate::types::address::Address; -use crate::types::governance::{ - self, Proposal, ProposalError, ProposalVote, VoteType, +use crate::ledger::governance::cli::onchain::{ + DefaultProposal, PgfFundingProposal, PgfStewardProposal, +}; +use crate::ledger::governance::storage::proposal::{ + AddRemove, PGFAction, ProposalType, }; +use crate::ledger::governance::storage::vote::StorageProposalVote; +use crate::types::address::Address; use crate::types::hash::Hash; use crate::types::storage::Epoch; -/// The type of a Proposal -#[derive( - Debug, - Clone, - PartialEq, - BorshSerialize, - BorshDeserialize, - Serialize, - Deserialize, -)] -pub enum ProposalType { - /// Default governance proposal with the optional wasm code - Default(Option), - /// PGF council proposal - PGFCouncil, - /// ETH proposal - ETHBridge, -} - -impl Display for ProposalType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - ProposalType::Default(_) => write!(f, "Default"), - ProposalType::PGFCouncil => write!(f, "PGF Council"), - ProposalType::ETHBridge => write!(f, "ETH Bridge"), - } - } -} - -impl PartialEq for ProposalType { - fn eq(&self, other: &VoteType) -> bool { - match self { - Self::Default(_) => { - matches!(other, VoteType::Default) - } - Self::PGFCouncil => { - matches!(other, VoteType::PGFCouncil(..)) - } - Self::ETHBridge => { - matches!(other, VoteType::ETHBridge(_)) - } - } - } -} - -impl TryFrom for (ProposalType, Option>) { - type Error = ProposalError; - - fn try_from(value: governance::ProposalType) -> Result { - match value { - governance::ProposalType::Default(path) => { - if let Some(p) = path { - match std::fs::read(p) { - Ok(code) => Ok(( - ProposalType::Default(Some(Hash::default())), - Some(code), - )), - Err(_) => Err(Self::Error::InvalidProposalData), - } - } else { - Ok((ProposalType::Default(None), None)) - } - } - governance::ProposalType::PGFCouncil => { - Ok((ProposalType::PGFCouncil, None)) - } - governance::ProposalType::ETHBridge => { - Ok((ProposalType::ETHBridge, None)) - } - } - } +#[allow(missing_docs)] +#[derive(Debug, Error)] +pub enum ProposalError { + #[error("Invalid proposal data.")] + InvalidProposalData, } /// A tx data type to hold proposal data @@ -110,6 +49,16 @@ pub struct InitProposalData { pub grace_epoch: Epoch, } +impl InitProposalData { + /// Get the hash of the corresponding extra data section + pub fn get_section_code_hash(&self) -> Option { + match self.r#type { + ProposalType::Default(hash) => hash, + _ => None, + } + } +} + /// A tx data type to hold vote proposal data #[derive( Debug, @@ -124,30 +73,82 @@ pub struct VoteProposalData { /// The proposal id pub id: u64, /// The proposal vote - pub vote: ProposalVote, + pub vote: StorageProposalVote, /// The proposal author address pub voter: Address, /// Delegator addreses pub delegations: Vec
, } -impl TryFrom for (InitProposalData, Vec, Option>) { +impl TryFrom for InitProposalData { + type Error = ProposalError; + + fn try_from(value: DefaultProposal) -> Result { + Ok(InitProposalData { + id: value.proposal.id, + content: Hash::default(), + author: value.proposal.author, + r#type: ProposalType::Default(None), + voting_start_epoch: value.proposal.voting_start_epoch, + voting_end_epoch: value.proposal.voting_end_epoch, + grace_epoch: value.proposal.grace_epoch, + }) + } +} + +impl TryFrom for InitProposalData { type Error = ProposalError; - fn try_from(proposal: Proposal) -> Result { - let (r#type, code) = proposal.r#type.try_into()?; - Ok(( - InitProposalData { - id: proposal.id, - content: Hash::default(), - author: proposal.author, - r#type, - voting_start_epoch: proposal.voting_start_epoch, - voting_end_epoch: proposal.voting_end_epoch, - grace_epoch: proposal.grace_epoch, - }, - proposal.content.try_to_vec().unwrap(), - code, - )) + fn try_from(value: PgfStewardProposal) -> Result { + let extra_data = value + .data + .iter() + .cloned() + .map(|steward| AddRemove::
::try_from(steward).unwrap()) + .collect::>>(); + + Ok(InitProposalData { + id: value.proposal.id, + content: Hash::default(), + author: value.proposal.author, + r#type: ProposalType::PGFSteward(extra_data), + voting_start_epoch: value.proposal.voting_start_epoch, + voting_end_epoch: value.proposal.voting_end_epoch, + grace_epoch: value.proposal.grace_epoch, + }) + } +} + +impl TryFrom for InitProposalData { + type Error = ProposalError; + + fn try_from(value: PgfFundingProposal) -> Result { + let continous_fundings = value + .data + .continous + .iter() + .cloned() + .map(|funding| PGFAction::try_from(funding).unwrap()) + .collect::>(); + + let retro_fundings = value + .data + .retro + .iter() + .cloned() + .map(|funding| PGFAction::try_from(funding).unwrap()) + .collect::>(); + + let extra_data = [continous_fundings, retro_fundings].concat(); + + Ok(InitProposalData { + id: value.proposal.id, + content: Hash::default(), + author: value.proposal.author, + r#type: ProposalType::PGFPayment(extra_data), + voting_start_epoch: value.proposal.voting_start_epoch, + voting_end_epoch: value.proposal.voting_end_epoch, + grace_epoch: value.proposal.grace_epoch, + }) } } diff --git a/core/src/types/transaction/mod.rs b/core/src/types/transaction/mod.rs index c6cc23dffa..112bc5de4b 100644 --- a/core/src/types/transaction/mod.rs +++ b/core/src/types/transaction/mod.rs @@ -1,5 +1,7 @@ //! Types that are used in transactions. +/// txs to manage accounts +pub mod account; /// txs that contain decrypted payloads or assertions of /// non-decryptability pub mod decrypted; @@ -7,6 +9,7 @@ pub mod decrypted; pub mod encrypted; /// txs to manage governance pub mod governance; +/// txs to manage pos pub mod pos; /// transaction protocols made by validators pub mod protocol; @@ -27,10 +30,8 @@ pub use wrapper::*; use crate::ledger::gas::VpsGas; use crate::types::address::Address; -use crate::types::dec::Dec; use crate::types::hash::Hash; use crate::types::ibc::IbcEvent; -use crate::types::key::*; use crate::types::storage; #[cfg(feature = "ferveo-tpke")] use crate::types::transaction::protocol::ProtocolTx; @@ -131,80 +132,6 @@ fn iterable_to_string( } } -/// A tx data type to update an account's validity predicate -#[derive( - Debug, - Clone, - PartialEq, - BorshSerialize, - BorshDeserialize, - BorshSchema, - Serialize, - Deserialize, -)] -pub struct UpdateVp { - /// An address of the account - pub addr: Address, - /// The new VP code hash - pub vp_code_hash: Hash, -} - -/// A tx data type to initialize a new established account -#[derive( - Debug, - Clone, - PartialEq, - BorshSerialize, - BorshDeserialize, - BorshSchema, - Serialize, - Deserialize, -)] -pub struct InitAccount { - /// Public key to be written into the account's storage. This can be used - /// for signature verification of transactions for the newly created - /// account. - pub public_key: common::PublicKey, - /// The VP code hash - pub vp_code_hash: Hash, -} - -/// A tx data type to initialize a new validator account. -#[derive( - Debug, - Clone, - PartialEq, - BorshSerialize, - BorshDeserialize, - BorshSchema, - Serialize, - Deserialize, -)] -pub struct InitValidator { - /// Public key to be written into the account's storage. This can be used - /// for signature verification of transactions for the newly created - /// account. - pub account_key: common::PublicKey, - /// A key to be used for signing blocks and votes on blocks. - pub consensus_key: common::PublicKey, - /// An Eth bridge governance public key - pub eth_cold_key: secp256k1::PublicKey, - /// An Eth bridge hot signing public key used for validator set updates and - /// cross-chain transactions - pub eth_hot_key: secp256k1::PublicKey, - /// Public key used to sign protocol transactions - pub protocol_key: common::PublicKey, - /// Serialization of the public session key used in the DKG - pub dkg_key: crate::types::key::dkg_session_keys::DkgPublicKey, - /// The initial commission rate charged for delegation rewards - pub commission_rate: Dec, - /// The maximum change allowed per epoch to the commission rate. This is - /// immutable once set here. - pub max_commission_rate_change: Dec, - /// The VP code for validator account - pub validator_vp_code_hash: Hash, -} - /// Struct that classifies that kind of Tx /// based on the contents of its data. #[derive( @@ -241,6 +168,7 @@ mod test_process_tx { use super::*; use crate::proto::{Code, Data, Section, Signature, Tx, TxError}; use crate::types::address::nam; + use crate::types::key::*; use crate::types::storage::Epoch; use crate::types::token::Amount; @@ -256,7 +184,7 @@ mod test_process_tx { /// data and returns an identical copy #[test] fn test_process_tx_raw_tx_no_data() { - let mut outer_tx = Tx::new(TxType::Raw); + let mut outer_tx = Tx::from_type(TxType::Raw); let code_sec = outer_tx .set_code(Code::new("wasm code".as_bytes().to_owned())) .clone(); @@ -274,7 +202,7 @@ mod test_process_tx { /// of the inner data #[test] fn test_process_tx_raw_tx_some_data() { - let mut tx = Tx::new(TxType::Raw); + let mut tx = Tx::from_type(TxType::Raw); let code_sec = tx .set_code(Code::new("wasm code".as_bytes().to_owned())) .clone(); @@ -296,7 +224,7 @@ mod test_process_tx { /// signed data and returns an identical copy of the inner data #[test] fn test_process_tx_raw_tx_some_signed_data() { - let mut tx = Tx::new(TxType::Raw); + let mut tx = Tx::from_type(TxType::Raw); let code_sec = tx .set_code(Code::new("wasm code".as_bytes().to_owned())) .clone(); @@ -324,7 +252,7 @@ mod test_process_tx { fn test_process_tx_wrapper_tx() { let keypair = gen_keypair(); // the signed tx - let mut tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( + let mut tx = Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( Fee { amount: Amount::from_uint(10, 0).expect("Test failed"), token: nam(), @@ -359,7 +287,7 @@ mod test_process_tx { fn test_process_tx_wrapper_tx_unsigned() { let keypair = gen_keypair(); // the signed tx - let mut tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( + let mut tx = Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( Fee { amount: Amount::from_uint(10, 0).expect("Test failed"), token: nam(), @@ -382,7 +310,7 @@ mod test_process_tx { #[test] fn test_process_tx_decrypted_unsigned() { use crate::proto::{Code, Data, Tx}; - let mut tx = Tx::new(TxType::Decrypted(DecryptedTx::Decrypted { + let mut tx = Tx::from_type(TxType::Decrypted(DecryptedTx::Decrypted { #[cfg(not(feature = "mainnet"))] has_valid_pow: false, })); @@ -411,6 +339,8 @@ fn test_process_tx_decrypted_unsigned() { #[test] fn test_process_tx_decrypted_signed() { use crate::proto::{Code, Data, Section, Signature, Tx}; + use crate::types::key::*; + fn gen_keypair() -> common::SecretKey { use rand::prelude::ThreadRng; use rand::thread_rng; @@ -420,10 +350,11 @@ fn test_process_tx_decrypted_signed() { } use crate::types::key::Signature as S; - let mut decrypted = Tx::new(TxType::Decrypted(DecryptedTx::Decrypted { - #[cfg(not(feature = "mainnet"))] - has_valid_pow: false, - })); + let mut decrypted = + Tx::from_type(TxType::Decrypted(DecryptedTx::Decrypted { + #[cfg(not(feature = "mainnet"))] + has_valid_pow: false, + })); // Invalid signed data let ed_sig = ed25519::Signature::try_from_slice([0u8; 64].as_ref()).unwrap(); diff --git a/core/src/types/transaction/pos.rs b/core/src/types/transaction/pos.rs index d334047ffe..fa0e3d0891 100644 --- a/core/src/types/transaction/pos.rs +++ b/core/src/types/transaction/pos.rs @@ -5,8 +5,48 @@ use serde::{Deserialize, Serialize}; use crate::types::address::Address; use crate::types::dec::Dec; +use crate::types::hash::Hash; +use crate::types::key::{common, secp256k1}; use crate::types::token; +/// A tx data type to initialize a new validator account. +#[derive( + Debug, + Clone, + PartialEq, + BorshSerialize, + BorshDeserialize, + BorshSchema, + Serialize, + Deserialize, +)] +pub struct InitValidator { + /// Public key to be written into the account's storage. This can be used + /// for signature verification of transactions for the newly created + /// account. + pub account_keys: Vec, + /// The minimum number of signatures needed + pub threshold: u8, + /// A key to be used for signing blocks and votes on blocks. + pub consensus_key: common::PublicKey, + /// An Eth bridge governance public key + pub eth_cold_key: secp256k1::PublicKey, + /// An Eth bridge hot signing public key used for validator set updates and + /// cross-chain transactions + pub eth_hot_key: secp256k1::PublicKey, + /// Public key used to sign protocol transactions + pub protocol_key: common::PublicKey, + /// Serialization of the public session key used in the DKG + pub dkg_key: crate::types::key::dkg_session_keys::DkgPublicKey, + /// The initial commission rate charged for delegation rewards + pub commission_rate: Dec, + /// The maximum change allowed per epoch to the commission rate. This is + /// immutable once set here. + pub max_commission_rate_change: Dec, + /// The VP code for validator account + pub validator_vp_code_hash: Hash, +} + /// A bond is a validator's self-bond or a delegation from non-validator to a /// validator. #[derive( diff --git a/core/src/types/transaction/protocol.rs b/core/src/types/transaction/protocol.rs index d546168bf4..aa9abe8cec 100644 --- a/core/src/types/transaction/protocol.rs +++ b/core/src/types/transaction/protocol.rs @@ -193,7 +193,7 @@ mod protocol_txs { ) -> Tx { let (tx_data, tx_type) = self.serialize(); let mut outer_tx = - Tx::new(TxType::Protocol(Box::new(ProtocolTx { + Tx::from_type(TxType::Protocol(Box::new(ProtocolTx { pk: signing_key.ref_to(), tx: tx_type, }))); @@ -323,7 +323,7 @@ mod protocol_txs { TX_NEW_DKG_KP_WASM, ); let mut outer_tx = - Tx::new(TxType::Protocol(Box::new(ProtocolTx { + Tx::from_type(TxType::Protocol(Box::new(ProtocolTx { pk: signing_key.ref_to(), tx: Self::NewDkgKeypair, }))); diff --git a/core/src/types/transaction/wrapper.rs b/core/src/types/transaction/wrapper.rs index 403641a0b6..321435687b 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 { @@ -255,7 +256,7 @@ pub mod wrapper_tx { /// Get the address of the implicit account associated /// with the public key - pub fn fee_payer(&self) -> Address { + pub fn gas_payer(&self) -> Address { Address::from(&self.pk) } @@ -370,7 +371,7 @@ pub mod wrapper_tx { fn test_encryption_round_trip() { let keypair = gen_keypair(); let mut wrapper = - Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( Fee { amount: Amount::from_uint(10, 0).expect("Test failed"), token: nam(), @@ -403,7 +404,7 @@ pub mod wrapper_tx { fn test_decryption_invalid_hash() { let keypair = gen_keypair(); let mut wrapper = - Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( Fee { amount: Amount::from_uint(10, 0).expect("Test failed"), token: nam(), @@ -438,17 +439,18 @@ pub mod wrapper_tx { fn test_malleability_attack_detection() { let keypair = gen_keypair(); // the signed tx - let mut tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: Amount::from_uint(10, 0).expect("Test failed"), - token: nam(), - }, - keypair.ref_to(), - Epoch(0), - Default::default(), - #[cfg(not(feature = "mainnet"))] - None, - )))); + let mut tx = + Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new( + Fee { + amount: Amount::from_uint(10, 0).expect("Test failed"), + token: nam(), + }, + keypair.ref_to(), + Epoch(0), + Default::default(), + #[cfg(not(feature = "mainnet"))] + None, + )))); tx.set_code(Code::new("wasm code".as_bytes().to_owned())); tx.set_data(Data::new("transaction data".as_bytes().to_owned())); diff --git a/documentation/dev/src/explore/design/ledger/governance.md b/documentation/dev/src/explore/design/ledger/governance.md index d9e578eed5..a7215c79b2 100644 --- a/documentation/dev/src/explore/design/ledger/governance.md +++ b/documentation/dev/src/explore/design/ledger/governance.md @@ -13,7 +13,7 @@ Also, it introduces some protocol parameters: - `min_proposal_fund` - `max_proposal_code_size` -- `min_proposal_period` +- `min_proposal_voting_period` - `max_proposal_period` - `max_proposal_content_size` - `min_proposal_grace_epochs` @@ -26,7 +26,7 @@ On-chain proposals are created under the `governance_address` storage space and, /$GovernanceAddress/counter: u64 /$GovernanceAddress/min_proposal_fund: u64 /$GovernanceAddress/max_proposal_code_size: u64 -/$GovernanceAddress/min_proposal_period: u64 +/$GovernanceAddress/min_proposal_voting_period: u64 /$GovernanceAddress/max_proposal_period: u64 /$GovernanceAddress/max_proposal_content_size: u64 /$GovernanceAddress/min_proposal_grace_epochs: u64 @@ -50,11 +50,11 @@ and follow these rules: - `$id` must be equal to `counter + 1`. - `startEpoch` must: - be greater than `currentEpoch`, where current epoch is the epoch in which the transaction is executed and included in a block - - be a multiple of `min_proposal_period`. + - be a multiple of `min_proposal_voting_period`. - `endEpoch` must: - - be at least `min_proposal_period` epochs greater than `startEpoch` + - be at least `min_proposal_voting_period` epochs greater than `startEpoch` - be at most `max_proposal_period` epochs greater than `startEpoch` - - be a multiple of `min_proposal_period` + - be a multiple of `min_proposal_voting_period` - `graceEpoch` must: - be at least `min_grace_epoch` epochs greater than `endEpoch` - `proposalCode` can be empty and must be a valid transaction with size less than `max_proposal_code_size` kibibytes. diff --git a/documentation/dev/src/specs/ledger/default-transactions.md b/documentation/dev/src/specs/ledger/default-transactions.md index fb254f0cd3..d1e36b923a 100644 --- a/documentation/dev/src/specs/ledger/default-transactions.md +++ b/documentation/dev/src/specs/ledger/default-transactions.md @@ -28,7 +28,7 @@ Transparently transfer `amount` of fungible `token` from the `source` to the `ta Attach [Transfer](../encoding.md#transfer) to the `data`. -### tx_update_vp +### tx_update_account Update a validity predicate of an established account. diff --git a/encoding_spec/src/main.rs b/encoding_spec/src/main.rs index b9e2b034ef..5889b03b8d 100644 --- a/encoding_spec/src/main.rs +++ b/encoding_spec/src/main.rs @@ -70,10 +70,13 @@ fn main() -> Result<(), Box> { let public_key_schema = PublicKey::schema_container(); // TODO update after let signature_schema = Signature::schema_container(); - let init_account_schema = transaction::InitAccount::schema_container(); - let init_validator_schema = transaction::InitValidator::schema_container(); + let init_account_schema = + transaction::account::InitAccount::schema_container(); + let init_validator_schema = + transaction::pos::InitValidator::schema_container(); let token_transfer_schema = token::Transfer::schema_container(); - let update_vp_schema = transaction::UpdateVp::schema_container(); + let update_account = + transaction::account::UpdateAccount::schema_container(); let pos_bond_schema = pos::Bond::schema_container(); let pos_withdraw_schema = pos::Withdraw::schema_container(); let wrapper_tx_schema = transaction::WrapperTx::schema_container(); @@ -98,7 +101,7 @@ fn main() -> Result<(), Box> { definitions.extend(init_account_schema.definitions); definitions.extend(init_validator_schema.definitions); definitions.extend(token_transfer_schema.definitions); - definitions.extend(update_vp_schema.definitions); + definitions.extend(update_account.definitions); definitions.extend(pos_bond_schema.definitions); definitions.extend(pos_withdraw_schema.definitions); definitions.extend(wrapper_tx_schema.definitions); @@ -179,11 +182,11 @@ fn main() -> Result<(), Box> { ).with_rust_doc_link("https://dev.namada.net/master/rustdoc/namada/types/token/struct.Transfer.html"); tables.push(token_transfer_table); - let update_vp_definition = - definitions.remove(&update_vp_schema.declaration).unwrap(); - let update_vp_table = - definition_to_table(update_vp_schema.declaration, update_vp_definition).with_rust_doc_link("https://dev.namada.net/master/rustdoc/namada/types/transaction/struct.UpdateVp.html"); - tables.push(update_vp_table); + let update_account_definition = + definitions.remove(&update_account.declaration).unwrap(); + let update_accoun_table = + definition_to_table(update_account.declaration, update_account_definition).with_rust_doc_link("https://dev.namada.net/master/rustdoc/namada/types/transaction/struct.UpdateVp.html"); + tables.push(update_accoun_table); let pos_bond_definition = definitions.remove(&pos_bond_schema.declaration).unwrap(); diff --git a/genesis/dev.toml b/genesis/dev.toml index 19985a3b9e..9121bc1a10 100644 --- a/genesis/dev.toml +++ b/genesis/dev.toml @@ -1,148 +1,203 @@ -# Example genesis with dev settings. -genesis_time = "2021-09-30:10:00.00Z" +# Developer network +genesis_time = "2021-12-20T15:00:00.00Z" native_token = "NAM" - -# A genesis validator with alias "validator". -[validator.validator] -# Validator's public key for consensus. -consensus_public_key = "5e704c4e46265e1ccc87505149f79b9d2e414d01a4e3806dfc65f0a73901c1d0" -# Public key of the validator's Namada account. -account_public_key = "5e704c4e46265e1ccc87505149f79b9d2e414d01a4e3806dfc65f0a73901c1d0" -# Address of the validator. -address = "a1qq5qqqqqgfqnsd6pxse5zdj9g5crzsf5x4zyzv6yxerr2d2rxpryzwp5g5m5zvfjxv6ygsekjmraj0" -# Validator's token balance at genesis. -tokens = 200000 -# Amount of the validator's genesis token balance which is not staked. -non_staked_balance = 100000 -# VP for the validator account -validator_vp = "vp_validator" -# Commission rate for rewards -commission_rate = "0.05" -# Maximum change per epoch in the commission rate -max_commission_rate_change = "0.01" -# Public IP:port address -net_address = "127.0.0.1:26656" +faucet_pow_difficulty = 0 +faucet_withdrawal_limit = "1000" # Some tokens present at genesis. [token.NAM] address = "atest1v4ehgw36x3prswzxggunzv6pxqmnvdj9xvcyzvpsggeyvs3cg9qnywf589qnwvfsg5erg3fkl09rg5" -denom = 8 +denom = 6 +vp = "vp_token" [token.NAM.balances] -# In token balances, we can use: -# 1. An address any account -a1qyqzsqqqqqcyvvf5xcu5vd6rg4z5233hg9pn23pjgdryzdjy8pz52wzxxscnvvjxx3rryvzz8y5p6mtz = 1000000 -atest1v4ehgw36x3qng3jzggu5yvpsxgcngv2xgguy2dpkgvu5x33kx3pr2w2zgep5xwfkxscrxs2pj8075p = 1000000 -atest1v4ehgw36xvcyyvejgvenxs34g3zygv3jxqunjd6rxyeyys3sxy6rwvfkx4qnj33hg9qnvse4lsfctw = 1000000 -# 2. An alias of any account +Albert = "1000000" +"Albert.public_key" = "100" Bertha = "1000000" -# 3. A public key of a validator or an established account from which the -# address of the implicit account is derived) -"bertha.public_key" = 100 -"validator.public_key" = 100 +"Bertha.public_key" = "2000" +Christel = "1000000" +"Christel.public_key" = "100" +Daewon = "1000000" +Ester = "1000000" +faucet = "922337203685400000000" +"faucet.public_key" = "100" +[token.NAM.parameters] +max_reward_rate = "0.1" +kd_gain_nom = "0.1" +kp_gain_nom = "0.1" +locked_ratio_target_key = "0.6667" [token.BTC] address = "atest1v4ehgw36xdzryve5gsc52veeg5cnsv2yx5eygvp38qcrvd29xy6rys6p8yc5xvp4xfpy2v694wgwcp" denom = 8 +vp = "vp_token" [token.BTC.balances] -atest1v4ehgw368ycryv2z8qcnxv3cxgmrgvjpxs6yg333gym5vv2zxepnj334g4rryvj9xucrgve4x3xvr4 = 1000000 -atest1v4ehgw36x3qng3jzggu5yvpsxgcngv2xgguy2dpkgvu5x33kx3pr2w2zgep5xwfkxscrxs2pj8075p = 1000000 -atest1v4ehgw36xvcyyvejgvenxs34g3zygv3jxqunjd6rxyeyys3sxy6rwvfkx4qnj33hg9qnvse4lsfctw = 1000000 -a1qyqzsqqqqqcyvvf5xcu5vd6rg4z5233hg9pn23pjgdryzdjy8pz52wzxxscnvvjxx3rryvzz8y5p6mtz = 1000000 +Albert = "1000000" +Bertha = "1000000" +Christel = "1000000" +Daewon = "1000000" +Ester = "1000000" +faucet = "9223372036854" +[token.BTC.parameters] +max_reward_rate = "0.1" +kd_gain_nom = "0.1" +kp_gain_nom = "0.1" +locked_ratio_target_key = "0.6667" [token.ETH] address = "atest1v4ehgw36xqmr2d3nx3ryvd2xxgmrq33j8qcns33sxezrgv6zxdzrydjrxveygd2yxumrsdpsf9jc2p" denom = 18 +vp = "vp_token" [token.ETH.balances] -atest1v4ehgw368ycryv2z8qcnxv3cxgmrgvjpxs6yg333gym5vv2zxepnj334g4rryvj9xucrgve4x3xvr4 = 1000000 -atest1v4ehgw36x3qng3jzggu5yvpsxgcngv2xgguy2dpkgvu5x33kx3pr2w2zgep5xwfkxscrxs2pj8075p = 1000000 -atest1v4ehgw36xvcyyvejgvenxs34g3zygv3jxqunjd6rxyeyys3sxy6rwvfkx4qnj33hg9qnvse4lsfctw = 1000000 -a1qyqzsqqqqqcyvvf5xcu5vd6rg4z5233hg9pn23pjgdryzdjy8pz52wzxxscnvvjxx3rryvzz8y5p6mtz = 1000000 +Albert = "1000000" +Bertha = "1000000" +Christel = "1000000" +Daewon = "1000000" +Ester = "1000000" +faucet = "9223372036854" +[token.ETH.parameters] +max_reward_rate = "0.1" +kd_gain_nom = "0.1" +kp_gain_nom = "0.1" +locked_ratio_target_key = "0.6667" [token.DOT] address = "atest1v4ehgw36gg6nvs2zgfpyxsfjgc65yv6pxy6nwwfsxgungdzrggeyzv35gveyxsjyxymyz335hur2jn" denom = 10 +vp = "vp_token" [token.DOT.balances] -atest1v4ehgw368ycryv2z8qcnxv3cxgmrgvjpxs6yg333gym5vv2zxepnj334g4rryvj9xucrgve4x3xvr4 = 1000000 -atest1v4ehgw36x3qng3jzggu5yvpsxgcngv2xgguy2dpkgvu5x33kx3pr2w2zgep5xwfkxscrxs2pj8075p = 1000000 -atest1v4ehgw36xvcyyvejgvenxs34g3zygv3jxqunjd6rxyeyys3sxy6rwvfkx4qnj33hg9qnvse4lsfctw = 1000000 -a1qyqzsqqqqqcyvvf5xcu5vd6rg4z5233hg9pn23pjgdryzdjy8pz52wzxxscnvvjxx3rryvzz8y5p6mtz = 1000000 +Albert = "1000000" +Bertha = "1000000" +Christel = "1000000" +Daewon = "1000000" +Ester = "1000000" +faucet = "9223372036854" +[token.DOT.parameters] +max_reward_rate = "0.1" +kd_gain_nom = "0.1" +kp_gain_nom = "0.1" +locked_ratio_target_key = "0.6667" -[token.schnitzel] +[token.Schnitzel] address = "atest1v4ehgw36xue5xvf5xvuyzvpjx5un2v3k8qeyvd3cxdqns32p89rrxd6xx9zngvpegccnzs699rdnnt" denom = 6 -[token.schnitzel.balances] -atest1v4ehgw368ycryv2z8qcnxv3cxgmrgvjpxs6yg333gym5vv2zxepnj334g4rryvj9xucrgve4x3xvr4 = 1000000 -atest1v4ehgw36x3qng3jzggu5yvpsxgcngv2xgguy2dpkgvu5x33kx3pr2w2zgep5xwfkxscrxs2pj8075p = 1000000 -atest1v4ehgw36xvcyyvejgvenxs34g3zygv3jxqunjd6rxyeyys3sxy6rwvfkx4qnj33hg9qnvse4lsfctw = 1000000 -a1qyqzsqqqqqcyvvf5xcu5vd6rg4z5233hg9pn23pjgdryzdjy8pz52wzxxscnvvjxx3rryvzz8y5p6mtz = 1000000 +vp = "vp_token" +[token.Schnitzel.balances] +Albert = "1000000" +Bertha = "1000000" +Christel = "1000000" +Daewon = "1000000" +Ester = "1000000" +faucet = "9223372036854" +[token.Schnitzel.parameters] +max_reward_rate = "0.1" +kd_gain_nom = "0.1" +kp_gain_nom = "0.1" +locked_ratio_target_key = "0.6667" -[token.apfel] +[token.Apfel] address = "atest1v4ehgw36gfryydj9g3p5zv3kg9znyd358ycnzsfcggc5gvecgc6ygs2rxv6ry3zpg4zrwdfeumqcz9" denom = 6 -[token.apfel.balances] -atest1v4ehgw368ycryv2z8qcnxv3cxgmrgvjpxs6yg333gym5vv2zxepnj334g4rryvj9xucrgve4x3xvr4 = 1000000 -atest1v4ehgw36x3qng3jzggu5yvpsxgcngv2xgguy2dpkgvu5x33kx3pr2w2zgep5xwfkxscrxs2pj8075p = 1000000 -atest1v4ehgw36xvcyyvejgvenxs34g3zygv3jxqunjd6rxyeyys3sxy6rwvfkx4qnj33hg9qnvse4lsfctw = 1000000 -a1qyqzsqqqqqcyvvf5xcu5vd6rg4z5233hg9pn23pjgdryzdjy8pz52wzxxscnvvjxx3rryvzz8y5p6mtz = 1000000 +vp = "vp_token" +[token.Apfel.balances] +Albert = "1000000" +Bertha = "1000000" +Christel = "1000000" +Daewon = "1000000" +Ester = "1000000" +faucet = "9223372036854" +[token.Apfel.parameters] +max_reward_rate = "0.1" +kd_gain_nom = "0.1" +kp_gain_nom = "0.1" +locked_ratio_target_key = "0.6667" -[token.kartoffel] +[token.Kartoffel] address = "atest1v4ehgw36gep5ysecxq6nyv3jg3zygv3e89qn2vp48pryxsf4xpznvve5gvmy23fs89pryvf5a6ht90" -denom = 6 public_key = "" -[token.kartoffel.balances] -atest1v4ehgw368ycryv2z8qcnxv3cxgmrgvjpxs6yg333gym5vv2zxepnj334g4rryvj9xucrgve4x3xvr4 = 1000000 -atest1v4ehgw36x3qng3jzggu5yvpsxgcngv2xgguy2dpkgvu5x33kx3pr2w2zgep5xwfkxscrxs2pj8075p = 1000000 -atest1v4ehgw36xvcyyvejgvenxs34g3zygv3jxqunjd6rxyeyys3sxy6rwvfkx4qnj33hg9qnvse4lsfctw = 1000000 -a1qyqzsqqqqqcyvvf5xcu5vd6rg4z5233hg9pn23pjgdryzdjy8pz52wzxxscnvvjxx3rryvzz8y5p6mtz = 1000000 +denom = 6 +vp = "vp_token" +[token.Kartoffel.balances] +Albert = "1000000" +Bertha = "1000000" +Christel = "1000000" +Daewon = "1000000" +Ester = "1000000" +faucet = "9223372036854" +[token.Kartoffel.parameters] +max_reward_rate = "0.1" +kd_gain_nom = "0.1" +kp_gain_nom = "0.1" +locked_ratio_target_key = "0.6667" # Some established accounts present at genesis. +[established.faucet] +vp = "vp_testnet_faucet" -[established.albert] -address = "atest1v4ehgw368ycryv2z8qcnxv3cxgmrgvjpxs6yg333gym5vv2zxepnj334g4rryvj9xucrgve4x3xvr4" -public_key = "a57281e1dd9fd39ec3e8a162a1643ca7c836c0f2dae3bef1412a3a61a2fde1a7" +[established.Albert] vp = "vp_user" -[established.bertha] -address = "atest1v4ehgw36xvcyyvejgvenxs34g3zygv3jxqunjd6rxyeyys3sxy6rwvfkx4qnj33hg9qnvse4lsfctw" -public_key = "572512a95b190d615b1987f7072572a64951ad50f4f97ef9dbb83545c46ae600" +[established.Bertha] vp = "vp_user" -[established.christel] -address = "atest1v4ehgw36x3qng3jzggu5yvpsxgcngv2xgguy2dpkgvu5x33kx3pr2w2zgep5xwfkxscrxs2pj8075p" -public_key = "d06f8d4f897f329a50fd23ba5d2503bbe22fab2f14d5f625e07a65f617eb2778" +[established.Christel] vp = "vp_user" -# An implicit account present at genesis. +[established.masp] +address = "atest1v4ehgw36xaryysfsx5unvve4g5my2vjz89p52sjxxgenzd348yuyyv3hg3pnjs35g5unvde4ca36y5" +vp = "vp_masp" + +[implicit.Daewon] -# Daewon (a1qyqzsqqqqqcyvvf5xcu5vd6rg4z5233hg9pn23pjgdryzdjy8pz52wzxxscnvvjxx3rryvzz8y5p6mtz) -[implicit.daewon] -public_key = "2b5b8fda66fb6fc4ef0d86f84b21f250034077effc459fc2403a77a35aa95e3f" +[implicit.Ester] # Wasm VP definitions -# Default user VP +# Wasm VP definitions + +# Implicit VP +[wasm.vp_implicit] +filename = "vp_implicit.wasm" + +# Default user VP in established accounts [wasm.vp_user] -# filename (relative to wasm path used by the node) filename = "vp_user.wasm" -# SHA-256 hash of the wasm file -sha256 = "dc7b97f0448f2369bd2401c3c1d8898f53cac8c464a8c1b1f7f81415a658625d" # Default validator VP [wasm.vp_validator] # filename (relative to wasm path used by the node) filename = "vp_validator.wasm" +# Faucet VP +[wasm.vp_testnet_faucet] +filename = "vp_testnet_faucet.wasm" + +# MASP VP +[wasm.vp_masp] +filename = "vp_masp.wasm" + # General protocol parameters. [parameters] # Minimum number of blocks in an epoch. -min_num_of_blocks = 10 +min_num_of_blocks = 4 # Maximum expected time per block (in seconds). max_expected_time_per_block = 30 -# Expected epochs per year (also sets the minimum duration of an epoch in seconds) -epochs_per_year = 525_600 # Max payload size, in bytes, for a tx batch proposal. max_proposal_bytes = 22020096 +# vp whitelist +vp_whitelist = [] +# tx whitelist +tx_whitelist = [] +# Implicit VP WASM name +implicit_vp = "vp_implicit" +# Expected number of epochs per year (also sets the min duration of an epoch in seconds) +epochs_per_year = 105_120 # 5 minute epochs +# The P gain factor in the Proof of Stake rewards controller +pos_gain_p = "0.1" +# The D gain factor in the Proof of Stake rewards controller +pos_gain_d = "0.1" +# The maximum number of signatures allowed per transaction +max_signatures_per_transaction = 15 # Proof of stake parameters. [pos_params] @@ -153,9 +208,9 @@ max_validator_slots = 128 pipeline_len = 2 # Unbonding length (in epochs). Validators may have their stake slashed # for a fault in epoch 'n' up through epoch 'n + unbonding_len'. -unbonding_len = 21 +unbonding_len = 3 # Votes per fundamental staking token (namnam) -tm_votes_per_token = "1" +tm_votes_per_token = "0.1" # Reward for proposing a block. block_proposer_reward = "0.125" # Reward for voting on a block. @@ -173,18 +228,29 @@ light_client_attack_min_slash_rate = "0.001" # Number of epochs above and below (separately) the current epoch to # consider when doing cubic slashing cubic_slashing_window_length = 1 +# The minimum amount of bonded tokens that a validator needs to be in +# either the `consensus` or `below_capacity` validator sets +validator_stake_threshold = "1" # Governance parameters. [gov_params] -# minimum amount of NAM token to lock +# minimum amount of nam token to lock min_proposal_fund = 500 # proposal code size in bytes -max_proposal_code_size = 300000 -# min proposal period length in epochs -min_proposal_period = 3 +max_proposal_code_size = 500000 +# min proposal voting period length in epochs +min_proposal_voting_period = 3 # max proposal period length in epochs max_proposal_period = 27 # maximum number of characters in the proposal content -max_proposal_content_size = 5000 +max_proposal_content_size = 10000 # minimum epochs between end and grace epoch min_proposal_grace_epochs = 6 + +[pgf_params] +# list of steward address at genezis +stewards = [] +# inflation rate for pgf fundings +pgf_inflation_rate = "0.1" +# inflation rate for pgf stewards +stewards_inflation_rate = "0.01" \ No newline at end of file diff --git a/genesis/e2e-tests-single-node.toml b/genesis/e2e-tests-single-node.toml index 83f02b3c8e..45df21e09a 100644 --- a/genesis/e2e-tests-single-node.toml +++ b/genesis/e2e-tests-single-node.toml @@ -4,7 +4,7 @@ genesis_time = "2021-09-30T10:00:00Z" native_token = "NAM" -faucet_pow_difficulty = 1 +faucet_pow_difficulty = 0 faucet_withdrawal_limit = "1000" [validator.validator-0] @@ -174,6 +174,8 @@ epochs_per_year = 31_536_000 pos_gain_p = "0.1" # The D gain factor in the Proof of Stake rewards controller pos_gain_d = "0.1" +# The maximum number of signatures allowed per transaction +max_signatures_per_transaction = 15 # Proof of stake parameters. [pos_params] @@ -215,10 +217,18 @@ min_proposal_fund = 500 # proposal code size in bytes max_proposal_code_size = 1000000 # min proposal period length in epochs -min_proposal_period = 3 +min_proposal_voting_period = 3 # max proposal period length in epochs max_proposal_period = 27 # maximum number of characters in the proposal content max_proposal_content_size = 10000 # minimum epochs between end and grace epoch min_proposal_grace_epochs = 6 + +[pgf_params] +# list of steward address at genezis +stewards = [] +# inflation rate for pgf fundings +pgf_inflation_rate = "0.1" +# inflation rate for pgf stewards +stewards_inflation_rate = "0.01" \ No newline at end of file diff --git a/proof_of_stake/src/lib.rs b/proof_of_stake/src/lib.rs index 4c087dbbd6..c18a626268 100644 --- a/proof_of_stake/src/lib.rs +++ b/proof_of_stake/src/lib.rs @@ -869,7 +869,7 @@ pub fn is_validator( address: &Address, ) -> storage_api::Result where - S: StorageRead + StorageWrite, + S: StorageRead, { let rate = read_validator_max_commission_rate_change(storage, address)?; Ok(rate.is_some()) @@ -3927,11 +3927,8 @@ where // Check that the validator is jailed up to the pipeline epoch for epoch in current_epoch.iter_range(params.pipeline_len + 1) { - let state = validator_state_handle(validator).get( - storage, - current_epoch, - ¶ms, - )?; + let state = + validator_state_handle(validator).get(storage, epoch, ¶ms)?; if let Some(state) = state { if state != ValidatorState::Jailed { return Err(UnjailValidatorError::NotJailed( diff --git a/proof_of_stake/src/tests.rs b/proof_of_stake/src/tests.rs index 6476827417..b7463c8ea5 100644 --- a/proof_of_stake/src/tests.rs +++ b/proof_of_stake/src/tests.rs @@ -51,9 +51,10 @@ use crate::{ staking_token_address, store_total_consensus_stake, total_deltas_handle, unbond_handle, unbond_tokens, unjail_validator, update_validator_deltas, update_validator_set, validator_consensus_key_handle, - validator_set_update_tendermint, validator_slashes_handle, - validator_state_handle, withdraw_tokens, write_validator_address_raw_hash, - BecomeValidator, STORE_VALIDATOR_SETS_LEN, + validator_set_positions_handle, validator_set_update_tendermint, + validator_slashes_handle, validator_state_handle, withdraw_tokens, + write_validator_address_raw_hash, BecomeValidator, + STORE_VALIDATOR_SETS_LEN, }; proptest! { @@ -124,6 +125,22 @@ proptest! { } } +proptest! { + // Generate arb valid input for `test_unjail_validator_aux` + #![proptest_config(Config { + cases: 5, + .. Config::default() + })] + #[test] + fn test_unjail_validator( + (pos_params, genesis_validators) + in arb_params_and_genesis_validators(Some(4),6..9) + ) { + test_unjail_validator_aux(pos_params, + genesis_validators) + } +} + fn arb_params_and_genesis_validators( num_max_validator_slots: Option, val_size: Range, @@ -2112,3 +2129,127 @@ fn arb_genesis_validators( }, ) } + +fn test_unjail_validator_aux( + params: PosParams, + mut validators: Vec, +) { + println!("\nTest inputs: {params:?}, genesis validators: {validators:#?}"); + let mut s = TestWlStorage::default(); + + // Find the validator with the most stake and 100x his stake to keep the + // cubic slash rate small + let num_vals = validators.len(); + validators.sort_by_key(|a| a.tokens); + validators[num_vals - 1].tokens = 100 * validators[num_vals - 1].tokens; + + // Get second highest stake validator tomisbehave + let val_addr = &validators[num_vals - 2].address; + let val_tokens = validators[num_vals - 2].tokens; + println!( + "Validator that will misbehave addr {val_addr}, tokens {}", + val_tokens.to_string_native() + ); + + // Genesis + let mut current_epoch = s.storage.block.epoch; + init_genesis( + &mut s, + ¶ms, + validators.clone().into_iter(), + current_epoch, + ) + .unwrap(); + s.commit_block().unwrap(); + + current_epoch = advance_epoch(&mut s, ¶ms); + super::process_slashes(&mut s, current_epoch).unwrap(); + + // Discover first slash + let slash_0_evidence_epoch = current_epoch; + let evidence_block_height = BlockHeight(0); // doesn't matter for slashing logic + let slash_0_type = SlashType::DuplicateVote; + slash( + &mut s, + ¶ms, + current_epoch, + slash_0_evidence_epoch, + evidence_block_height, + slash_0_type, + val_addr, + current_epoch.next(), + ) + .unwrap(); + + assert_eq!( + validator_state_handle(val_addr) + .get(&s, current_epoch, ¶ms) + .unwrap(), + Some(ValidatorState::Consensus) + ); + + for epoch in Epoch::iter_bounds_inclusive( + current_epoch.next(), + current_epoch + params.pipeline_len, + ) { + // Check the validator state + assert_eq!( + validator_state_handle(val_addr) + .get(&s, epoch, ¶ms) + .unwrap(), + Some(ValidatorState::Jailed) + ); + // Check the validator set positions + assert!( + validator_set_positions_handle() + .at(&epoch) + .get(&s, val_addr) + .unwrap() + .is_none(), + ); + } + + // Advance past an epoch in which we can unbond + let unfreeze_epoch = + slash_0_evidence_epoch + params.slash_processing_epoch_offset(); + while current_epoch < unfreeze_epoch + 4u64 { + current_epoch = advance_epoch(&mut s, ¶ms); + super::process_slashes(&mut s, current_epoch).unwrap(); + } + + // Unjail the validator + unjail_validator(&mut s, val_addr, current_epoch).unwrap(); + + // Check the validator state + for epoch in + Epoch::iter_bounds_inclusive(current_epoch, current_epoch.next()) + { + assert_eq!( + validator_state_handle(val_addr) + .get(&s, epoch, ¶ms) + .unwrap(), + Some(ValidatorState::Jailed) + ); + } + + assert_eq!( + validator_state_handle(val_addr) + .get(&s, current_epoch + params.pipeline_len, ¶ms) + .unwrap(), + Some(ValidatorState::Consensus) + ); + assert!( + validator_set_positions_handle() + .at(&(current_epoch + params.pipeline_len)) + .get(&s, val_addr) + .unwrap() + .is_some(), + ); + + // Advance another epoch + current_epoch = advance_epoch(&mut s, ¶ms); + super::process_slashes(&mut s, current_epoch).unwrap(); + + let second_att = unjail_validator(&mut s, val_addr, current_epoch); + assert!(second_att.is_err()); +} diff --git a/scripts/generator.sh b/scripts/generator.sh index 701f8fbabe..3fe1792a49 100755 --- a/scripts/generator.sh +++ b/scripts/generator.sh @@ -212,79 +212,79 @@ elif [ "$1" = "client" ]; then # proposal_submission - cargo run --bin namadac --features std -- --mode full bond --validator validator-0 --source Bertha --amount 900 --gas-amount 0 --gas-limit 0 --gas-token NAM --node 127.0.0.1:27657 + cargo run --bin namadac --features std -- bond --validator validator-0 --source Bertha --amount 900 --gas-amount 0 --gas-limit 0 --gas-token NAM --node 127.0.0.1:27657 - cargo run --bin namadac --features std -- --mode full change-commission-rate --validator Bertha --commission-rate 0.02 --gas-amount 0 --gas-limit 0 --gas-token NAM --force --node 127.0.0.1:27657 + cargo run --bin namadac --features std -- change-commission-rate --validator Bertha --commission-rate 0.02 --gas-amount 0 --gas-limit 0 --gas-token NAM --force --node 127.0.0.1:27657 - PROPOSAL_ID_0=$(cargo run --bin namadac --features std -- --mode full init-proposal --force --data-path proposal_submission_valid_proposal.json --node 127.0.0.1:27657 | grep -o -P '(?<=/proposal/).*(?=/author)') + PROPOSAL_ID_0=$(cargo run --bin namadac --features std -- init-proposal --force --data-path proposal_submission_valid_proposal.json --node 127.0.0.1:27657 | grep -o -P '(?<=/proposal/).*(?=/author)') - cargo run --bin namadac --features std -- --base-dir $NAMADA_BASE_DIR/setup/validator-0/.namada --mode validator vote-proposal --force --proposal-id $PROPOSAL_ID_0 --vote yay --signer validator-0 --node 127.0.0.1:27657 + cargo run --bin namadac --features std -- --base-dir $NAMADA_BASE_DIR/setup/validator-0/.namada vote-proposal --force --proposal-id $PROPOSAL_ID_0 --vote yay --address validator-0 --node 127.0.0.1:27657 - cargo run --bin namadac --features std -- --mode full vote-proposal --force --proposal-id $PROPOSAL_ID_0 --vote nay --signer Bertha --node 127.0.0.1:27657 + cargo run --bin namadac --features std -- vote-proposal --force --proposal-id $PROPOSAL_ID_0 --vote nay --address Bertha --node 127.0.0.1:27657 - cargo run --bin namadac --features std -- --mode full vote-proposal --force --proposal-id $PROPOSAL_ID_0 --vote yay --signer Albert --node 127.0.0.1:27657 + cargo run --bin namadac --features std -- vote-proposal --force --proposal-id $PROPOSAL_ID_0 --vote yay --address Albert --node 127.0.0.1:27657 # proposal_offline - cargo run --bin namadac --features std -- --mode full bond --validator validator-0 --source Albert --amount 900 --gas-amount 0 --gas-limit 0 --gas-token NAM --node 127.0.0.1:27657 + cargo run --bin namadac --features std -- bond --validator validator-0 --source Albert --amount 900 --gas-amount 0 --gas-limit 0 --gas-token NAM --node 127.0.0.1:27657 - cargo run --bin namadac --features std -- --mode full change-commission-rate --validator Albert --commission-rate 0.05 --gas-amount 0 --gas-limit 0 --gas-token NAM --force --node 127.0.0.1:27657 + cargo run --bin namadac --features std -- change-commission-rate --validator Albert --commission-rate 0.05 --gas-amount 0 --gas-limit 0 --gas-token NAM --force --node 127.0.0.1:27657 - cargo run --bin namadac --features std -- --mode full init-proposal --force --data-path proposal_offline_valid_proposal.json --offline --node 127.0.0.1:27657 + cargo run --bin namadac --features std -- init-proposal --force --data-path proposal_offline_valid_proposal.json --offline --node 127.0.0.1:27657 - cargo run --bin namadac --features std -- --mode full vote-proposal --data-path proposal_offline_proposal --vote yay --signer Albert --offline --node 127.0.0.1:27657 + cargo run --bin namadac --features std -- vote-proposal --data-path proposal_offline_proposal --vote yay --address Albert --offline --node 127.0.0.1:27657 # eth_governance_proposal - cargo run --bin namadac --features std -- --mode full bond --validator validator-0 --source Bertha --amount 900 --gas-amount 0 --gas-limit 0 --gas-token NAM --ledger-address 127.0.0.1:27657 + cargo run --bin namadac --features std -- bond --validator validator-0 --source Bertha --amount 900 --gas-amount 0 --gas-limit 0 --gas-token NAM --ledger-address 127.0.0.1:27657 - cargo run --bin namadac --features std -- --mode full change-commission-rate --validator Bertha --commission-rate 0.07 --gas-amount 0 --gas-limit 0 --gas-token NAM --force --node 127.0.0.1:27657 + cargo run --bin namadac --features std -- change-commission-rate --validator Bertha --commission-rate 0.07 --gas-amount 0 --gas-limit 0 --gas-token NAM --force --node 127.0.0.1:27657 - PROPOSAL_ID_0=$(cargo run --bin namadac --features std -- --mode full init-proposal --force --data-path eth_governance_proposal_valid_proposal.json --ledger-address 127.0.0.1:27657 | grep -o -P '(?<=/proposal/).*(?=/author)') + PROPOSAL_ID_0=$(cargo run --bin namadac --features std -- init-proposal --force --data-path eth_governance_proposal_valid_proposal.json --ledger-address 127.0.0.1:27657 | grep -o -P '(?<=/proposal/).*(?=/author)') - cargo run --bin namadac --features std -- --mode full vote-proposal --force --proposal-id 0 --vote yay --eth '011586062748ba53bc53155e817ec1ea708de75878dcb9a5713bf6986d87fe14e7 fd34672ab5' --signer Bertha --ledger-address 127.0.0.1:27657 + cargo run --bin namadac --features std -- vote-proposal --force --proposal-id 0 --vote yay --eth '011586062748ba53bc53155e817ec1ea708de75878dcb9a5713bf6986d87fe14e7 fd34672ab5' --address Bertha --ledger-address 127.0.0.1:27657 - cargo run --bin namadac --features std -- --base-dir $NAMADA_BASE_DIR/setup/validator-0/.namada --mode validator vote-proposal --force --proposal-id $PROPOSAL_ID_0 --vote yay --eth '011586062748ba53bc53155e817ec1ea708de75878dcb9a5713bf6986d87fe14e7 fd34672ab5' --signer validator-0 --ledger-address 127.0.0.1:27657 + cargo run --bin namadac --features std -- --base-dir $NAMADA_BASE_DIR/setup/validator-0/.namada vote-proposal --force --proposal-id $PROPOSAL_ID_0 --vote yay --eth '011586062748ba53bc53155e817ec1ea708de75878dcb9a5713bf6986d87fe14e7 fd34672ab5' --address validator-0 --ledger-address 127.0.0.1:27657 # pgf_governance_proposal - cargo run --bin namadac --features std -- --mode full bond --validator validator-0 --source Bertha --amount 900 --gas-amount 0 --gas-limit 0 --gas-token NAM --ledger-address 127.0.0.1:27657 + cargo run --bin namadac --features std -- bond --validator validator-0 --source Bertha --amount 900 --gas-amount 0 --gas-limit 0 --gas-token NAM --ledger-address 127.0.0.1:27657 - cargo run --bin namadac --features std -- --mode full change-commission-rate --validator Bertha --commission-rate 0.09 --gas-amount 0 --gas-limit 0 --gas-token NAM --force --node 127.0.0.1:27657 + cargo run --bin namadac --features std -- change-commission-rate --validator Bertha --commission-rate 0.09 --gas-amount 0 --gas-limit 0 --gas-token NAM --force --node 127.0.0.1:27657 - PROPOSAL_ID_0=$(cargo run --bin namadac --features std -- --mode full init-proposal --force --data-path pgf_governance_proposal_valid_proposal.json --ledger-address 127.0.0.1:27657 | grep -o -P '(?<=/proposal/).*(?=/author)') + PROPOSAL_ID_0=$(cargo run --bin namadac --features std -- init-proposal --force --data-path pgf_governance_proposal_valid_proposal.json --ledger-address 127.0.0.1:27657 | grep -o -P '(?<=/proposal/).*(?=/author)') - PROPOSAL_ID_1=$(cargo run --bin namadac --features std -- --mode full init-proposal --force --data-path pgf_governance_proposal_valid_proposal.json --ledger-address 127.0.0.1:27657 | grep -o -P '(?<=/proposal/).*(?=/author)') + PROPOSAL_ID_1=$(cargo run --bin namadac --features std -- init-proposal --force --data-path pgf_governance_proposal_valid_proposal.json --ledger-address 127.0.0.1:27657 | grep -o -P '(?<=/proposal/).*(?=/author)') - cargo run --bin namadac --features std -- --base-dir $NAMADA_BASE_DIR/setup/validator-0/.namada --mode validator vote-proposal --force --proposal-id $PROPOSAL_ID_0 --vote yay --pgf "$ALBERT_ADDRESS 1000" --signer validator-0 --ledger-address 127.0.0.1:27657 + cargo run --bin namadac --features std -- --base-dir $NAMADA_BASE_DIR/setup/validator-0/.namada vote-proposal --force --proposal-id $PROPOSAL_ID_0 --vote yay --pgf "$ALBERT_ADDRESS 1000" --address validator-0 --ledger-address 127.0.0.1:27657 - cargo run --bin namadac --features std -- --mode full vote-proposal --force --proposal-id $PROPOSAL_ID_0 --vote yay --pgf "$ALBERT_ADDRESS 900" --signer Bertha --ledger-address 127.0.0.1:27657 + cargo run --bin namadac --features std -- vote-proposal --force --proposal-id $PROPOSAL_ID_0 --vote yay --pgf "$ALBERT_ADDRESS 900" --address Bertha --ledger-address 127.0.0.1:27657 - cargo run --bin namadac --features std -- --mode full vote-proposal --force --proposal-id $PROPOSAL_ID_1 --vote yay --pgf "$ALBERT_ADDRESS 900" --signer Bertha --ledger-address 127.0.0.1:27657 + cargo run --bin namadac --features std -- vote-proposal --force --proposal-id $PROPOSAL_ID_1 --vote yay --pgf "$ALBERT_ADDRESS 900" --address Bertha --ledger-address 127.0.0.1:27657 # non-proposal tests - cargo run --bin namadac --features std -- transfer --source bertha --target christel --token btc --amount 23 --force --signing-key bertha-key --ledger-address 127.0.0.1:27657 + cargo run --bin namadac --features std -- transfer --source bertha --target christel --token btc --amount 23 --force --signing-keys bertha-key --ledger-address 127.0.0.1:27657 - cargo run --bin namadac --features std -- bond --validator bertha --amount 25 --signing-key bertha-key --force --ledger-address 127.0.0.1:27657 + cargo run --bin namadac --features std -- bond --validator bertha --amount 25 --signing-keys bertha-key --force --ledger-address 127.0.0.1:27657 - cargo run --bin namadac --features std -- --mode full change-commission-rate --validator Bertha --commission-rate 0.11 --gas-amount 0 --gas-limit 0 --gas-token NAM --force --node 127.0.0.1:27657 + cargo run --bin namadac --features std -- change-commission-rate --validator Bertha --commission-rate 0.11 --gas-amount 0 --gas-limit 0 --gas-token NAM --force --node 127.0.0.1:27657 - cargo run --bin namadac --features std -- reveal-pk --public-key albert-key --force --ledger-address 127.0.0.1:27657 + cargo run --bin namadac --features std -- reveal-pk --public-key albert-key --gas-payer albert-key --force --ledger-address 127.0.0.1:27657 - cargo run --bin namadac --features std -- update --code-path vp_user.wasm --address bertha --signing-key bertha-key --force --ledger-address 127.0.0.1:27657 + cargo run --bin namadac --features std -- update-account --code-path vp_user.wasm --address bertha --signing-keys bertha-key --force --ledger-address 127.0.0.1:27657 - cargo run --bin namadac --features std -- init-validator --alias bertha-validator --source bertha --commission-rate 0.05 --max-commission-rate-change 0.01 --signing-key bertha-key --unsafe-dont-encrypt --force --ledger-address 127.0.0.1:27657 + cargo run --bin namadac --features std -- init-validator --alias bertha-validator --account-keys bertha --commission-rate 0.05 --max-commission-rate-change 0.01 --signing-keys bertha-key --unsafe-dont-encrypt --force --ledger-address 127.0.0.1:27657 - cargo run --bin namadac --features std -- unbond --validator christel --amount 5 --signing-key christel-key --force --ledger-address 127.0.0.1:27657 + cargo run --bin namadac --features std -- unbond --validator christel --amount 5 --signing-keys christel-key --force --ledger-address 127.0.0.1:27657 - cargo run --bin namadac --features std -- withdraw --validator albert --signing-key albert-key --force --ledger-address 127.0.0.1:27657 + cargo run --bin namadac --features std -- withdraw --validator albert --signing-keys albert-key --force --ledger-address 127.0.0.1:27657 - cargo run --bin namadac --features std -- init-account --alias albert-account --source albert --public-key albert-key --signing-key albert-key --force --ledger-address 127.0.0.1:27657 + cargo run --bin namadac --features std -- init-account --alias albert-account --public-keys albert-key --signing-keys albert-key --force --ledger-address 127.0.0.1:27657 - cargo run --bin namadac --features std -- tx --code-path $NAMADA_DIR/wasm_for_tests/tx_no_op.wasm --data-path README.md --signing-key albert-key --force --ledger-address 127.0.0.1:27657 + cargo run --bin namadac --features std -- tx --code-path $NAMADA_DIR/wasm_for_tests/tx_no_op.wasm --data-path README.md --signing-keys albert-key --owner albert --force --ledger-address 127.0.0.1:27657 - cargo run --bin namadac --features std -- ibc-transfer --source bertha --receiver christel --token btc --amount 24 --channel-id channel-141 --signing-key bertha-key --force --ledger-address 127.0.0.1:27657 + cargo run --bin namadac --features std -- ibc-transfer --source bertha --receiver christel --token btc --amount 24 --channel-id channel-141 --signing-keys bertha-key --force --ledger-address 127.0.0.1:27657 cargo run --bin namadaw -- masp add --alias a_spending_key --value xsktest1qqqqqqqqqqqqqq9v0sls5r5de7njx8ehu49pqgmqr9ygelg87l5x8y4s9r0pjlvu69au6gn3su5ewneas486hdccyayx32hxvt64p3d0hfuprpgcgv2q9gdx3jvxrn02f0nnp3jtdd6f5vwscfuyum083cvfv4jun75ak5sdgrm2pthzj3sflxc0jx0edrakx3vdcngrfjmru8ywkguru8mxss2uuqxdlglaz6undx5h8w7g70t2es850g48xzdkqay5qs0yw06rtxcvedhsv --unsafe-dont-encrypt diff --git a/scripts/get_hermes.sh b/scripts/get_hermes.sh new file mode 100755 index 0000000000..cd63f48f86 --- /dev/null +++ b/scripts/get_hermes.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +set -Eo pipefail + +HERMES_MAJORMINOR="1.6" +HERMES_PATCH="0" +HERMES_SUFFIX="-namada-beta1" + +HERMES_REPO="https://github.com/heliaxdev/hermes" + +HERMES_VERSION="${HERMES_MAJORMINOR}.${HERMES_PATCH}${HERMES_SUFFIX}" + +TARGET_PATH="/usr/local/bin" +TMP_PATH="/tmp" + +error_exit() +{ + echo "Error: $1" >&2 + exit 1 +} + +read -r SYSTEM MACHINE <<< "$(uname -s -m)" + +if [[ $SYSTEM = "Darwin" ]]; then + SYSTEM="apple-darwin" +else + SYSTEM="unknown-linux-gnu" +fi + +ARCH="x86_64" +if [[ $MACHINE = "aarch64" ]] || [[ $MACHINE = "arm64" ]]; then + ARCH="aarch64" +fi + +RELEASE_URL=${HERMES_REPO}/releases/download/v${HERMES_VERSION}/hermes-v${HERMES_VERSION}-${ARCH}-${SYSTEM}.tar.gz +echo "$RELEASE_URL" + +curl -LsSfo "$TMP_PATH"/hermes.tar.gz "$RELEASE_URL" || error_exit "hermes release download failed" + +cd $TARGET_PATH +sudo tar -xvzf $TMP_PATH/hermes.tar.gz hermes || error_exit "hermes release extraction failed" diff --git a/shared/src/ledger/args.rs b/shared/src/ledger/args.rs index 029c77ff0e..2d426d5510 100644 --- a/shared/src/ledger/args.rs +++ b/shared/src/ledger/args.rs @@ -99,9 +99,13 @@ pub struct TxCustom { /// Common tx arguments pub tx: Tx, /// Path to the tx WASM code file - pub code_path: C::Data, + pub code_path: Option, /// Path to the data file pub data_path: Option, + /// Path to the serialized transaction + pub serialized_tx: Option, + /// The address that correspond to the signatures/signing-keys + pub owner: C::Address, } /// Transfer transaction arguments @@ -155,6 +159,46 @@ pub struct TxIbcTransfer { pub timeout_height: Option, /// Timeout timestamp offset pub timeout_sec_offset: Option, + /// Memo + pub memo: Option, + /// Path to the TX WASM code file + pub tx_code_path: PathBuf, +} + +/// Transaction to initialize create a new proposal +#[derive(Clone, Debug)] +pub struct InitProposal { + /// Common tx arguments + pub tx: Tx, + /// The proposal data + pub proposal_data: C::Data, + /// Native token address + pub native_token: C::NativeAddress, + /// Flag if proposal should be run offline + pub is_offline: bool, + /// Flag if proposal is of type Pgf stewards + pub is_pgf_stewards: bool, + /// Flag if proposal is of type Pgf funding + pub is_pgf_funding: bool, + /// Path to the tx WASM file + pub tx_code_path: PathBuf, +} + +/// Transaction to vote on a proposal +#[derive(Clone, Debug)] +pub struct VoteProposal { + /// Common tx arguments + pub tx: Tx, + /// Proposal id + pub proposal_id: Option, + /// The vote + pub vote: String, + /// The address of the voter + pub voter: C::Address, + /// Flag if proposal vote should be run offline + pub is_offline: bool, + /// The proposal file path + pub proposal_data: Option, /// Path to the TX WASM code file pub tx_code_path: PathBuf, } @@ -164,14 +208,14 @@ pub struct TxIbcTransfer { pub struct TxInitAccount { /// Common tx arguments pub tx: Tx, - /// Address of the source account - pub source: C::Address, /// Path to the VP WASM code file for the new account pub vp_code_path: PathBuf, /// Path to the TX WASM code file pub tx_code_path: PathBuf, /// Public key for the new account - pub public_key: C::PublicKey, + pub public_keys: Vec, + /// The account multisignature threshold + pub threshold: Option, } /// Transaction to initialize a new account @@ -179,12 +223,12 @@ pub struct TxInitAccount { pub struct TxInitValidator { /// Common tx arguments pub tx: Tx, - /// Source - pub source: C::Address, /// Signature scheme pub scheme: SchemeType, - /// Account key - pub account_key: Option, + /// Account keys + pub account_keys: Vec, + /// The account multisignature threshold + pub threshold: Option, /// Consensus key pub consensus_key: Option, /// Ethereum cold key @@ -207,15 +251,19 @@ pub struct TxInitValidator { /// Transaction to update a VP arguments #[derive(Clone, Debug)] -pub struct TxUpdateVp { +pub struct TxUpdateAccount { /// Common tx arguments pub tx: Tx, /// Path to the VP WASM code file - pub vp_code_path: PathBuf, + pub vp_code_path: Option, /// Path to the TX WASM code file pub tx_code_path: PathBuf, /// Address of the account whose VP is to be updated pub addr: C::Address, + /// Public keys + pub public_keys: Vec, + /// The account threshold + pub threshold: Option, } /// Bond arguments @@ -277,6 +325,13 @@ pub struct QueryProtocolParameters { pub query: Query, } +/// Query pgf data +#[derive(Clone, Debug)] +pub struct QueryPgf { + /// Common query args + pub query: Query, +} + /// Withdraw arguments #[derive(Clone, Debug)] pub struct Withdraw { @@ -302,6 +357,15 @@ pub struct QueryConversions { pub epoch: Option, } +/// Query token balance(s) +#[derive(Clone, Debug)] +pub struct QueryAccount { + /// Common query args + pub query: Query, + /// Address of an owner + pub owner: C::Address, +} + /// Query token balance(s) #[derive(Clone, Debug)] pub struct QueryBalance { @@ -383,6 +447,17 @@ pub struct TxUnjailValidator { pub tx_code_path: PathBuf, } +#[derive(Clone, Debug)] +/// Sign a transaction offline +pub struct SignTx { + /// Common tx arguments + pub tx: Tx, + /// Transaction data + pub tx_data: C::Data, + /// The account address + pub owner: C::Address, +} + /// Query PoS commission rate #[derive(Clone, Debug)] pub struct QueryCommissionRate { @@ -435,8 +510,10 @@ pub struct QueryRawBytes { pub struct Tx { /// Simulate applying the transaction pub dry_run: bool, - /// Dump the transaction bytes + /// Dump the transaction bytes to file pub dump_tx: bool, + /// The output directory path to where serialize the data + pub output_folder: Option, /// Submit the transaction even if it doesn't pass client checks pub force: bool, /// Do not wait for the transaction to be added to the blockchain @@ -449,10 +526,12 @@ pub struct Tx { /// Whether to force overwrite the above alias, if it is provided, in the /// wallet. pub wallet_alias_force: bool, + /// The fee payer signing key + pub gas_payer: Option, /// The amount being payed to include the transaction - pub fee_amount: InputAmount, + pub gas_amount: InputAmount, /// The token in which the fee is being paid - pub fee_token: C::Address, + pub gas_token: C::Address, /// The max amount of gas used to process tx pub gas_limit: GasLimit, /// The optional expiration of the transaction @@ -460,9 +539,9 @@ pub struct Tx { /// The chain id for which the transaction is intended pub chain_id: Option, /// Sign the tx with the key for the given alias from your wallet - pub signing_key: Option, - /// Sign the tx with the keypair of the public key of the given address - pub signer: Option, + pub signing_keys: Vec, + /// List of signatures to attach to the transaction + pub signatures: Vec, /// Path to the TX WASM code file to reveal PK pub tx_reveal_code_path: PathBuf, /// Sign the tx with the public key for the given alias from your wallet @@ -633,11 +712,11 @@ pub struct EthereumBridgePool { /// The amount to be transferred pub amount: InputAmount, /// The amount of fees (in NAM) - pub gas_amount: token::Amount, + pub fee_amount: token::Amount, /// The account of fee payer. - pub gas_payer: C::Address, + pub fee_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 235941eb6a..b63eac52a8 100644 --- a/shared/src/ledger/eth_bridge/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/bridge_pool.rs @@ -17,11 +17,9 @@ 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::proto::Tx; use crate::types::address::Address; use crate::types::control_flow::time::{Duration, Instant}; use crate::types::control_flow::{ @@ -31,69 +29,70 @@ use crate::types::eth_abi::Encode; use crate::types::eth_bridge_pool::{ GasFee, PendingTransfer, TransferToEthereum, }; +use crate::types::io::Io; use crate::types::keccak::KeccakHash; use crate::types::token::{Amount, DenominatedAmount}; -use crate::types::transaction::TxType; use crate::types::voting_power::FractionalVotingPower; +use crate::{display, display_line}; /// 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, IO: Io, >( client: &C, - wallet: &mut Wallet, - args: args::EthereumBridgePool, -) -> Result<(Tx, Option
, common::PublicKey), Error> { - let args::EthereumBridgePool { - ref tx, + args::EthereumBridgePool { + tx: tx_args, asset, recipient, sender, amount, - gas_amount, - gas_payer, - code_path: wasm_code, - } = args; - let DenominatedAmount { amount, .. } = - validate_amount::<_, IO>(client, amount, &BRIDGE_ADDRESS, tx.force) - .await - .expect("Failed to validate amount"); + fee_amount, + fee_payer, + code_path, + }: args::EthereumBridgePool, + gas_payer: common::PublicKey, +) -> Result { + let DenominatedAmount { amount, .. } = validate_amount::<_, IO>( + client, + amount, + &BRIDGE_ADDRESS, + tx_args.force, + ) + .await + .expect("Failed to validate amount"); + let transfer = PendingTransfer { transfer: TransferToEthereum { asset, recipient, - sender, + sender: sender.clone(), amount, }, gas_fee: GasFee { - amount: gas_amount, - payer: gas_payer, + amount: fee_amount, + payer: fee_payer, }, }; - 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"), - )); - // TODO: change the wasm code to a hash - transfer_tx.set_code(Code::new(wasm_code)); - - prepare_tx::( + let tx_code_hash = + query_wasm_code_hash::<_, IO>(client, code_path.to_str().unwrap()) + .await + .unwrap(); + let chain_id = tx_args.chain_id.clone().unwrap(); + let mut tx = Tx::new(chain_id, tx_args.expiration); + tx.add_code_from_hash(tx_code_hash).add_data(transfer); + + prepare_tx::( client, - wallet, - tx, - transfer_tx, - TxSigningKey::None, + &tx_args, + &mut tx, + gas_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) - .await + .await; + Ok(tx) } /// A json serializable representation of the Ethereum @@ -875,6 +874,3 @@ mod recommendations { } pub use recommendations::recommend_batch; - -use crate::types::io::Io; -use crate::{display, display_line}; diff --git a/shared/src/ledger/events.rs b/shared/src/ledger/events.rs index 03e68417e2..0b5aa0253b 100644 --- a/shared/src/ledger/events.rs +++ b/shared/src/ledger/events.rs @@ -10,7 +10,7 @@ use std::str::FromStr; use borsh::{BorshDeserialize, BorshSerialize}; use thiserror::Error; -use crate::ledger::native_vp::governance::utils::ProposalEvent; +use crate::ledger::governance::utils::ProposalEvent; use crate::tendermint_proto::abci::EventAttribute; use crate::types::ibc::IbcEvent; #[cfg(feature = "ferveo-tpke")] @@ -50,6 +50,8 @@ pub enum EventType { Ibc(String), /// The proposal that has been executed Proposal, + /// The pgf payment + PgfPayment, } impl Display for EventType { @@ -59,6 +61,7 @@ impl Display for EventType { EventType::Applied => write!(f, "applied"), EventType::Ibc(t) => write!(f, "{}", t), EventType::Proposal => write!(f, "proposal"), + EventType::PgfPayment => write!(f, "pgf_payment"), }?; Ok(()) } @@ -72,6 +75,7 @@ impl FromStr for EventType { "accepted" => Ok(EventType::Accepted), "applied" => Ok(EventType::Applied), "proposal" => Ok(EventType::Proposal), + "pgf_payments" => Ok(EventType::PgfPayment), // IBC "update_client" => Ok(EventType::Ibc("update_client".to_string())), "send_packet" => Ok(EventType::Ibc("send_packet".to_string())), diff --git a/shared/src/ledger/events/log/dumb_queries.rs b/shared/src/ledger/events/log/dumb_queries.rs index 08dad37cd0..5ff7c8d54f 100644 --- a/shared/src/ledger/events/log/dumb_queries.rs +++ b/shared/src/ledger/events/log/dumb_queries.rs @@ -67,7 +67,6 @@ impl QueryMatcher { use crate::ibc::core::ics02_client::events::{ CLIENT_ID_ATTRIBUTE_KEY, CONSENSUS_HEIGHTS_ATTRIBUTE_KEY, }; - use crate::ibc::events::IbcEventType; let mut attributes = HashMap::new(); attributes @@ -79,9 +78,7 @@ impl QueryMatcher { .to_string(), ); Self { - event_type: EventType::Ibc( - IbcEventType::UpdateClient.as_str().to_string(), - ), + event_type: EventType::Ibc("update_client".to_string()), attributes, } } diff --git a/shared/src/ledger/native_vp/governance/mod.rs b/shared/src/ledger/governance/mod.rs similarity index 50% rename from shared/src/ledger/native_vp/governance/mod.rs rename to shared/src/ledger/governance/mod.rs index d41242a477..595df35cf3 100644 --- a/shared/src/ledger/native_vp/governance/mod.rs +++ b/shared/src/ledger/governance/mod.rs @@ -4,19 +4,25 @@ pub mod utils; use std::collections::BTreeSet; -use namada_core::ledger::governance::storage as gov_storage; -use namada_core::ledger::storage; +use borsh::BorshDeserialize; +use namada_core::ledger::governance::storage::keys as gov_storage; +use namada_core::ledger::governance::storage::proposal::{ + AddRemove, ProposalType, +}; +use namada_core::ledger::governance::storage::vote::StorageProposalVote; +use namada_core::ledger::governance::utils::is_valid_validator_voting_period; +use namada_core::ledger::storage_api::governance::is_proposal_accepted; use namada_core::ledger::vp_env::VpEnv; -use namada_core::types::governance::{ProposalVote, VoteType}; -use namada_core::types::transaction::governance::ProposalType; +use namada_core::ledger::{pgf, storage}; +use namada_core::proto::Tx; +use namada_proof_of_stake::is_validator; use thiserror::Error; -use utils::is_valid_validator_voting_period; +use self::utils::ReadType; use crate::ledger::native_vp::{Ctx, NativeVp}; use crate::ledger::storage_api::StorageRead; use crate::ledger::{native_vp, pos}; -use crate::proto::Tx; -use crate::types::address::Address; +use crate::types::address::{Address, InternalAddress}; use crate::types::storage::{Epoch, Key}; use crate::types::token; use crate::vm::WasmCacheAccess; @@ -24,11 +30,23 @@ use crate::vm::WasmCacheAccess; /// for handling Governance NativeVP errors pub type Result = std::result::Result; +/// The governance internal address +pub const ADDRESS: Address = Address::Internal(InternalAddress::Governance); + +/// The maximum number of item in a pgf proposal +pub const MAX_PGF_ACTIONS: usize = 20; + #[allow(missing_docs)] #[derive(Error, Debug)] pub enum Error { #[error("Native VP error: {0}")] NativeVpError(#[from] native_vp::Error), + #[error("Proposal field should not be empty: {0}")] + EmptyProposalField(String), + #[error("Vote key is not valid: {0}")] + InvalidVoteKey(String), + #[error("Vote type is not compatible with proposal type.")] + InvalidVoteType, } /// Governance VP @@ -99,13 +117,7 @@ where (KeyType::PROPOSAL_COMMIT, _) => { self.is_valid_proposal_commit() } - (KeyType::PARAMETER, _) => self.is_valid_parameter( - if let Some(data) = &tx_data.data() { - data - } else { - return false; - }, - ), + (KeyType::PARAMETER, _) => self.is_valid_parameter(tx_data), (KeyType::BALANCE, _) => self.is_valid_balance(&native_token), (KeyType::UNKNOWN_GOVERNANCE, _) => Ok(false), (KeyType::UNKNOWN, _) => Ok(true), @@ -126,10 +138,9 @@ where { fn is_valid_key_set(&self, keys: &BTreeSet) -> Result<(bool, u64)> { let counter_key = gov_storage::get_counter_key(); - let pre_counter: u64 = - self.ctx.pre().read(&counter_key)?.unwrap_or_default(); + let pre_counter: u64 = self.force_read(&counter_key, ReadType::Pre)?; let post_counter: u64 = - self.ctx.post().read(&counter_key)?.unwrap_or_default(); + self.force_read(&counter_key, ReadType::Post)?; if post_counter < pre_counter { return Ok((false, 0)); @@ -150,7 +161,7 @@ where gov_storage::get_grace_epoch_key(counter), ]); - // Check that expected set is a subset the actual one + // Check that expected set is a subset of the actual one if !keys.is_superset(&mandatory_keys) { return Ok((false, 0)); } @@ -170,122 +181,80 @@ where gov_storage::get_voting_start_epoch_key(proposal_id); let voting_end_epoch_key = gov_storage::get_voting_end_epoch_key(proposal_id); + let proposal_type_key = gov_storage::get_proposal_type_key(proposal_id); - let current_epoch = self.ctx.get_block_epoch().ok(); + let current_epoch = self.ctx.get_block_epoch()?; - let pre_counter: Option = self.ctx.pre().read(&counter_key)?; - let pre_voting_start_epoch: Option = - self.ctx.pre().read(&voting_start_epoch_key)?; - let pre_voting_end_epoch: Option = - self.ctx.pre().read(&voting_end_epoch_key)?; + let pre_counter: u64 = self.force_read(&counter_key, ReadType::Pre)?; + let pre_voting_start_epoch: Epoch = + self.force_read(&voting_start_epoch_key, ReadType::Pre)?; + let pre_voting_end_epoch: Epoch = + self.force_read(&voting_end_epoch_key, ReadType::Pre)?; + let proposal_type: ProposalType = + self.force_read(&proposal_type_key, ReadType::Pre)?; let voter = gov_storage::get_voter_address(key); let delegation_address = gov_storage::get_vote_delegation_address(key); - let vote: Option = self.ctx.read_post(key)?; - let proposal_type_key = gov_storage::get_proposal_type_key(proposal_id); - let proposal_type: Option = - self.ctx.read_pre(&proposal_type_key)?; - - match ( - pre_counter, - proposal_type, - vote, - voter, - delegation_address, + let vote: StorageProposalVote = self.force_read(key, ReadType::Post)?; + + let (voter_address, delegation_address) = + match (voter, delegation_address) { + (Some(voter_address), Some(delegator_address)) => { + (voter_address, delegator_address) + } + _ => return Err(Error::InvalidVoteKey(key.to_string())), + }; + + // Invalid proposal id + if pre_counter <= proposal_id { + return Ok(false); + } + + // Voted outside of voting window. We dont check for validator because + // if the proposal type is validator, we need to let + // them vote for the entire voting window. + if !self.is_valid_voting_window( current_epoch, pre_voting_start_epoch, pre_voting_end_epoch, + false, ) { - ( - Some(pre_counter), - Some(proposal_type), - Some(vote), - Some(voter_address), - Some(delegation_address), - Some(current_epoch), - Some(pre_voting_start_epoch), - Some(pre_voting_end_epoch), - ) => { - if pre_counter <= proposal_id { - // Invalid proposal id - return Ok(false); - } - if current_epoch < pre_voting_start_epoch - || current_epoch > pre_voting_end_epoch - { - // Voted outside of voting window - return Ok(false); - } - - if let ProposalVote::Yay(vote_type) = vote { - if proposal_type != vote_type { - return Ok(false); - } + return Ok(false); + } - // Vote type specific checks - if let VoteType::PGFCouncil(set) = vote_type { - // Check that all the addresses are established - for (address, _) in set { - match address { - Address::Established(_) => { - // Check that established address exists in - // storage - let vp_key = - Key::validity_predicate(&address); - if !self.ctx.has_key_pre(&vp_key)? { - return Ok(false); - } - } - _ => return Ok(false), - } - } - } else if let VoteType::ETHBridge(_sig) = vote_type { - // TODO: Check the validity of the signature with the - // governance ETH key in storage for the given validator - // - } - } + if !vote.is_compatible(&proposal_type) { + return Err(Error::InvalidVoteType); + } - match proposal_type { - ProposalType::Default(_) | ProposalType::PGFCouncil => { - if self - .is_validator( - pre_voting_start_epoch, - verifiers, - voter_address, - delegation_address, - ) - .unwrap_or(false) - { - Ok(is_valid_validator_voting_period( - current_epoch, - pre_voting_start_epoch, - pre_voting_end_epoch, - )) - } else { - Ok(self - .is_delegator( - pre_voting_start_epoch, - verifiers, - voter_address, - delegation_address, - ) - .unwrap_or(false)) - } - } - ProposalType::ETHBridge => Ok(self - .is_validator( - pre_voting_start_epoch, - verifiers, - voter_address, - delegation_address, - ) - .unwrap_or(false)), - } - } - _ => Ok(false), + // first check if validator, then check if delegator + let is_validator = self + .is_validator( + pre_voting_start_epoch, + verifiers, + voter_address, + delegation_address, + ) + .unwrap_or(false); + + if is_validator { + let valid_voting_period = is_valid_validator_voting_period( + current_epoch, + pre_voting_start_epoch, + pre_voting_end_epoch, + ); + return Ok(valid_voting_period); } + + let is_delegator = self + .is_delegator( + pre_voting_start_epoch, + verifiers, + voter_address, + delegation_address, + ) + .unwrap_or(false); + Ok(is_delegator) } /// Validate a content key @@ -299,39 +268,78 @@ where return Ok(false); } - let max_content_length: Option = - self.ctx.pre().read(&max_content_length_parameter_key)?; - let post_content: Option> = - self.ctx.read_bytes_post(&content_key)?; + let max_content_length: usize = + self.force_read(&max_content_length_parameter_key, ReadType::Pre)?; + let post_content = + self.ctx.read_bytes_post(&content_key)?.unwrap_or_default(); - match (post_content, max_content_length) { - (Some(post_content), Some(max_content_length)) => { - Ok(post_content.len() < max_content_length) - } - _ => Ok(false), - } + Ok(post_content.len() < max_content_length) } /// Validate the proposal type pub fn is_valid_proposal_type(&self, proposal_id: u64) -> Result { let proposal_type_key = gov_storage::get_proposal_type_key(proposal_id); - Ok(self - .ctx - .read_post::(&proposal_type_key)? - .is_some()) + let proposal_type: ProposalType = + self.force_read(&proposal_type_key, ReadType::Post)?; + + match proposal_type { + ProposalType::PGFSteward(stewards) => { + let steward_added = stewards + .iter() + .filter_map(|steward| match steward { + AddRemove::Add(address) => Some(address), + AddRemove::Remove(_) => None, + }) + .cloned() + .collect::>(); + + if steward_added.len() > 1 { + Ok(false) + } else if steward_added.is_empty() { + return Ok(stewards.len() < MAX_PGF_ACTIONS); + } else { + match steward_added.get(0) { + Some(address) => { + let author_key = + gov_storage::get_author_key(proposal_id); + let author = + self.force_read(&author_key, ReadType::Post)?; + return Ok(stewards.len() < MAX_PGF_ACTIONS + && address.eq(&author)); + } + None => return Ok(false), + } + } + } + ProposalType::PGFPayment(payments) => { + if payments.len() < MAX_PGF_ACTIONS { + return Ok(true); + } + let stewards_key = pgf::storage::keys::get_stewards_key(); + let author_key = gov_storage::get_author_key(proposal_id); + + let author: Option
= + self.ctx.pre().read(&author_key)?; + let stewards: BTreeSet
= + self.force_read(&stewards_key, ReadType::Pre)?; + + match author { + Some(address) => Ok(stewards.contains(&address)), + None => Ok(false), + } + } + _ => Ok(true), // default proposal + } } /// Validate a proposal code pub fn is_valid_proposal_code(&self, proposal_id: u64) -> Result { - let proposal_type_key: Key = - gov_storage::get_proposal_type_key(proposal_id); - let proposal_type: Option = - self.ctx.read_post(&proposal_type_key)?; + let proposal_type_key = gov_storage::get_proposal_type_key(proposal_id); + let proposal_type: ProposalType = + self.force_read(&proposal_type_key, ReadType::Post)?; - // Check that the proposal type admits wasm code - match proposal_type { - Some(ProposalType::Default(_)) => (), - _ => return Ok(false), + if !proposal_type.is_default() { + return Ok(false); } let code_key = gov_storage::get_proposal_code_key(proposal_id); @@ -343,22 +351,21 @@ where return Ok(false); } - let max_proposal_length: Option = - self.ctx.pre().read(&max_code_size_parameter_key)?; - let post_code: Option> = self.ctx.read_bytes_post(&code_key)?; + let max_proposal_length: usize = + self.force_read(&max_code_size_parameter_key, ReadType::Pre)?; + let post_code: Vec = + self.ctx.read_bytes_post(&code_key)?.unwrap_or_default(); - match (post_code, max_proposal_length) { - (Some(post_code), Some(max_content_length)) => { - Ok(post_code.len() < max_content_length) - } - _ => Ok(false), - } + Ok(post_code.len() <= max_proposal_length) } /// Validate a grace_epoch key pub fn is_valid_grace_epoch(&self, proposal_id: u64) -> Result { + let start_epoch_key = + gov_storage::get_voting_start_epoch_key(proposal_id); let end_epoch_key = gov_storage::get_voting_end_epoch_key(proposal_id); let grace_epoch_key = gov_storage::get_grace_epoch_key(proposal_id); + let max_proposal_period = gov_storage::get_max_proposal_period_key(); let min_grace_epoch_key = gov_storage::get_min_proposal_grace_epoch_key(); @@ -367,27 +374,32 @@ where return Ok(false); } - let end_epoch: Option = self.ctx.post().read(&end_epoch_key)?; - let grace_epoch: Option = - self.ctx.post().read(&grace_epoch_key)?; - let min_grace_epoch: Option = - self.ctx.pre().read(&min_grace_epoch_key)?; - match (min_grace_epoch, grace_epoch, end_epoch) { - (Some(min_grace_epoch), Some(grace_epoch), Some(end_epoch)) => { - let committing_epoch_key = - gov_storage::get_committing_proposals_key( - proposal_id, - grace_epoch, - ); - let has_post_committing_epoch = - self.ctx.has_key_post(&committing_epoch_key)?; - - Ok(has_post_committing_epoch - && end_epoch < grace_epoch - && grace_epoch - end_epoch >= min_grace_epoch) - } - _ => Ok(false), - } + let start_epoch: Epoch = + self.force_read(&start_epoch_key, ReadType::Post)?; + let end_epoch: Epoch = + self.force_read(&end_epoch_key, ReadType::Post)?; + let grace_epoch: Epoch = + self.force_read(&grace_epoch_key, ReadType::Post)?; + let min_grace_epoch: u64 = + self.force_read(&min_grace_epoch_key, ReadType::Pre)?; + let max_proposal_period: u64 = + self.force_read(&max_proposal_period, ReadType::Pre)?; + + let committing_epoch_key = gov_storage::get_committing_proposals_key( + proposal_id, + grace_epoch.into(), + ); + let has_post_committing_epoch = + self.ctx.has_key_post(&committing_epoch_key)?; + + let is_valid_grace_epoch = end_epoch < grace_epoch + && (grace_epoch - end_epoch).0 >= min_grace_epoch; + let is_valid_max_proposal_perido = start_epoch < grace_epoch + && grace_epoch.0 - start_epoch.0 <= max_proposal_period; + + Ok(has_post_committing_epoch + && is_valid_grace_epoch + && is_valid_max_proposal_perido) } /// Validate a start_epoch key @@ -396,9 +408,9 @@ where gov_storage::get_voting_start_epoch_key(proposal_id); let end_epoch_key = gov_storage::get_voting_end_epoch_key(proposal_id); let min_period_parameter_key = - gov_storage::get_min_proposal_period_key(); + gov_storage::get_min_proposal_voting_period_key(); - let current_epoch = self.ctx.get_block_epoch().ok(); + let current_epoch = self.ctx.get_block_epoch()?; let has_pre_start_epoch = self.ctx.has_key_pre(&start_epoch_key)?; let has_pre_end_epoch = self.ctx.has_key_pre(&end_epoch_key)?; @@ -407,27 +419,19 @@ where return Ok(false); } - let start_epoch: Option = - self.ctx.post().read(&start_epoch_key)?; - let end_epoch: Option = self.ctx.post().read(&end_epoch_key)?; - let min_period: Option = - self.ctx.pre().read(&min_period_parameter_key)?; - - match (min_period, start_epoch, end_epoch, current_epoch) { - ( - Some(min_period), - Some(start_epoch), - Some(end_epoch), - Some(current_epoch), - ) => { - if end_epoch <= start_epoch || start_epoch <= current_epoch { - return Ok(false); - } - Ok((end_epoch - start_epoch) % min_period == 0 - && (end_epoch - start_epoch).0 >= min_period) - } - _ => Ok(false), + let start_epoch: Epoch = + self.force_read(&start_epoch_key, ReadType::Post)?; + let end_epoch: Epoch = + self.force_read(&end_epoch_key, ReadType::Post)?; + let min_period: u64 = + self.force_read(&min_period_parameter_key, ReadType::Pre)?; + + if end_epoch <= start_epoch || start_epoch <= current_epoch { + return Ok(false); } + + Ok((end_epoch - start_epoch) % min_period == 0 + && (end_epoch - start_epoch).0 >= min_period) } /// Validate a end_epoch key @@ -436,11 +440,11 @@ where gov_storage::get_voting_start_epoch_key(proposal_id); let end_epoch_key = gov_storage::get_voting_end_epoch_key(proposal_id); let min_period_parameter_key = - gov_storage::get_min_proposal_period_key(); + gov_storage::get_min_proposal_voting_period_key(); let max_period_parameter_key = gov_storage::get_max_proposal_period_key(); - let current_epoch = self.ctx.get_block_epoch().ok(); + let current_epoch = self.ctx.get_block_epoch()?; let has_pre_start_epoch = self.ctx.has_key_pre(&start_epoch_key)?; let has_pre_end_epoch = self.ctx.has_key_pre(&end_epoch_key)?; @@ -449,36 +453,21 @@ where return Ok(false); } - let start_epoch: Option = - self.ctx.post().read(&start_epoch_key)?; - let end_epoch: Option = self.ctx.post().read(&end_epoch_key)?; - let min_period: Option = - self.ctx.pre().read(&min_period_parameter_key)?; - let max_period: Option = - self.ctx.pre().read(&max_period_parameter_key)?; - match ( - min_period, - max_period, - start_epoch, - end_epoch, - current_epoch, - ) { - ( - Some(min_period), - Some(max_period), - Some(start_epoch), - Some(end_epoch), - Some(current_epoch), - ) => { - if end_epoch <= start_epoch || start_epoch <= current_epoch { - return Ok(false); - } - Ok((end_epoch - start_epoch) % min_period == 0 - && (end_epoch - start_epoch).0 >= min_period - && (end_epoch - start_epoch).0 <= max_period) - } - _ => Ok(false), + let start_epoch: Epoch = + self.force_read(&start_epoch_key, ReadType::Post)?; + let end_epoch: Epoch = + self.force_read(&end_epoch_key, ReadType::Post)?; + let min_period: u64 = + self.force_read(&min_period_parameter_key, ReadType::Pre)?; + let max_period: u64 = + self.force_read(&max_period_parameter_key, ReadType::Pre)?; + + if end_epoch <= start_epoch || start_epoch <= current_epoch { + return Ok(false); } + Ok((end_epoch - start_epoch) % min_period == 0 + && (end_epoch - start_epoch).0 >= min_period + && (end_epoch - start_epoch).0 <= max_period) } /// Validate a funds key @@ -492,33 +481,20 @@ where token::balance_key(native_token_address, self.ctx.address); let min_funds_parameter_key = gov_storage::get_min_proposal_fund_key(); - let min_funds_parameter: Option = - self.ctx.pre().read(&min_funds_parameter_key)?; + let min_funds_parameter: token::Amount = + self.force_read(&min_funds_parameter_key, ReadType::Pre)?; let pre_balance: Option = self.ctx.pre().read(&balance_key)?; - let post_balance: Option = - self.ctx.post().read(&balance_key)?; - let post_funds: Option = - self.ctx.post().read(&funds_key)?; - - match (min_funds_parameter, pre_balance, post_balance, post_funds) { - ( - Some(min_funds_parameter), - Some(pre_balance), - Some(post_balance), - Some(post_funds), - ) => Ok(post_funds >= min_funds_parameter - && post_balance - pre_balance == post_funds), - ( - Some(min_funds_parameter), - None, - Some(post_balance), - Some(post_funds), - ) => { - Ok(post_funds >= min_funds_parameter - && post_balance == post_funds) - } - _ => Ok(false), + let post_balance: token::Amount = + self.force_read(&balance_key, ReadType::Post)?; + let post_funds: token::Amount = + self.force_read(&funds_key, ReadType::Post)?; + + if let Some(pre_balance) = pre_balance { + Ok(post_funds >= min_funds_parameter + && post_balance - pre_balance == post_funds) + } else { + Ok(post_funds >= min_funds_parameter && post_balance == post_funds) } } @@ -528,24 +504,19 @@ where token::balance_key(native_token_address, self.ctx.address); let min_funds_parameter_key = gov_storage::get_min_proposal_fund_key(); - let min_funds_parameter: Option = - self.ctx.pre().read(&min_funds_parameter_key)?; let pre_balance: Option = self.ctx.pre().read(&balance_key)?; - let post_balance: Option = - self.ctx.post().read(&balance_key)?; - - match (min_funds_parameter, pre_balance, post_balance) { - ( - Some(min_funds_parameter), - Some(pre_balance), - Some(post_balance), - ) => Ok(post_balance > pre_balance - && post_balance - pre_balance >= min_funds_parameter), - (Some(min_funds_parameter), None, Some(post_balance)) => { - Ok(post_balance >= min_funds_parameter) - } - _ => Ok(false), + + let min_funds_parameter: token::Amount = + self.force_read(&min_funds_parameter_key, ReadType::Pre)?; + let post_balance: token::Amount = + self.force_read(&balance_key, ReadType::Post)?; + + if let Some(pre_balance) = pre_balance { + Ok(post_balance > pre_balance + && post_balance - pre_balance >= min_funds_parameter) + } else { + Ok(post_balance >= min_funds_parameter) } } @@ -558,70 +529,61 @@ where let author_key = gov_storage::get_author_key(proposal_id); let has_pre_author = self.ctx.has_key_pre(&author_key)?; - if has_pre_author { return Ok(false); } - let author = self.ctx.post().read(&author_key)?; + let author = self.force_read(&author_key, ReadType::Post)?; match author { - Some(author) => match author { - Address::Established(_) => { - let address_exist_key = Key::validity_predicate(&author); - let address_exist = - self.ctx.has_key_post(&address_exist_key)?; + Address::Established(_) => { + let address_exist_key = Key::validity_predicate(&author); + let address_exist = + self.ctx.has_key_post(&address_exist_key)?; - Ok(address_exist && verifiers.contains(&author)) - } - Address::Implicit(_) => Ok(verifiers.contains(&author)), - Address::Internal(_) => Ok(false), - }, - _ => Ok(false), + Ok(address_exist && verifiers.contains(&author)) + } + Address::Implicit(_) => Ok(verifiers.contains(&author)), + Address::Internal(_) => Ok(false), } } /// Validate a counter key pub fn is_valid_counter(&self, set_count: u64) -> Result { let counter_key = gov_storage::get_counter_key(); - let pre_counter: Option = self.ctx.pre().read(&counter_key)?; - let post_counter: Option = self.ctx.post().read(&counter_key)?; + let pre_counter: u64 = self.force_read(&counter_key, ReadType::Pre)?; + let post_counter: u64 = + self.force_read(&counter_key, ReadType::Post)?; - match (pre_counter, post_counter) { - (Some(pre_counter), Some(post_counter)) => { - Ok(pre_counter + set_count == post_counter) - } - _ => Ok(false), - } + Ok(pre_counter + set_count == post_counter) } /// Validate a commit key pub fn is_valid_proposal_commit(&self) -> Result { let counter_key = gov_storage::get_counter_key(); - let pre_counter: Option = self.ctx.pre().read(&counter_key)?; - let post_counter: Option = self.ctx.post().read(&counter_key)?; - - match (pre_counter, post_counter) { - (Some(pre_counter), Some(post_counter)) => { - // NOTE: can't do pre_counter + set_count == post_counter here - // because someone may update an empty proposal that just - // register a committing key causing a bug - Ok(pre_counter < post_counter) - } - _ => Ok(false), - } + let pre_counter: u64 = self.force_read(&counter_key, ReadType::Pre)?; + let post_counter: u64 = + self.force_read(&counter_key, ReadType::Post)?; + + // NOTE: can't do pre_counter + set_count == post_counter here + // because someone may update an empty proposal that just + // register a committing key causing a bug + Ok(pre_counter < post_counter) } /// Validate a governance parameter - pub fn is_valid_parameter(&self, tx_data: &[u8]) -> Result { - utils::is_proposal_accepted(&self.ctx.pre(), tx_data) - .map_err(Error::NativeVpError) + pub fn is_valid_parameter(&self, tx: &Tx) -> Result { + match tx.data() { + Some(data) => is_proposal_accepted(&self.ctx.pre(), data.as_ref()) + .map_err(Error::NativeVpError), + None => Ok(true), + } } /// Check if a vote is from a validator pub fn is_validator( &self, - epoch: Epoch, + _epoch: Epoch, verifiers: &BTreeSet
, address: &Address, delegation_address: &Address, @@ -631,23 +593,47 @@ where H: 'static + storage::StorageHasher, CA: 'static + WasmCacheAccess, { - let all_validators = - pos::namada_proof_of_stake::read_all_validator_addresses( - &self.ctx.pre(), - epoch, - )?; - if !all_validators.is_empty() { - let is_voter_validator = all_validators - .into_iter() - .any(|validator| validator.eq(address)); - let is_signer_validator = verifiers.contains(address); - let is_delegation_address = delegation_address.eq(address); - - Ok(is_voter_validator - && is_signer_validator - && is_delegation_address) + if !address.eq(delegation_address) { + return Ok(false); + } + + let is_validator = is_validator(&self.ctx.pre(), address)?; + + Ok(is_validator && verifiers.contains(address)) + } + + /// Private method to read from storage data that are 100% in storage. + fn force_read(&self, key: &Key, read_type: ReadType) -> Result + where + T: BorshDeserialize, + { + let res = match read_type { + ReadType::Pre => self.ctx.pre().read::(key), + ReadType::Post => self.ctx.post().read::(key), + }?; + + if let Some(data) = res { + Ok(data) } else { - Ok(false) + Err(Error::EmptyProposalField(key.to_string())) + } + } + + fn is_valid_voting_window( + &self, + current_epoch: Epoch, + start_epoch: Epoch, + end_epoch: Epoch, + is_validator: bool, + ) -> bool { + if is_validator { + is_valid_validator_voting_period( + current_epoch, + start_epoch, + end_epoch, + ) + } else { + current_epoch >= start_epoch && current_epoch <= end_epoch } } @@ -659,10 +645,6 @@ where address: &Address, delegation_address: &Address, ) -> Result { - // let bond_key = pos::bond_key(&BondId { - // source: address.clone(), - // validator: delegation_address.clone(), - // }); let bond_handle = pos::namada_proof_of_stake::bond_handle( address, delegation_address, @@ -670,7 +652,6 @@ where let params = pos::namada_proof_of_stake::read_pos_params(&self.ctx.pre())?; let bond = bond_handle.get_sum(&self.ctx.pre(), epoch, ¶ms)?; - // let bonds: Option = self.ctx.pre().read(&bond_key)?; if bond.is_some() && verifiers.contains(address) { Ok(true) @@ -681,7 +662,7 @@ where } #[allow(clippy::upper_case_acronyms)] -#[derive(Clone, Debug)] +#[derive(Debug)] enum KeyType { #[allow(non_camel_case_types)] COUNTER, diff --git a/shared/src/ledger/governance/utils.rs b/shared/src/ledger/governance/utils.rs new file mode 100644 index 0000000000..d4b4d1316c --- /dev/null +++ b/shared/src/ledger/governance/utils.rs @@ -0,0 +1,122 @@ +//! Governance utility functions + +use std::collections::HashMap; + +use namada_core::ledger::governance::utils::TallyResult; +use thiserror::Error; + +use crate::ledger::events::EventType; + +pub(super) enum ReadType { + Pre, + Post, +} + +/// Proposal errors +#[derive(Error, Debug)] +pub enum Error { + /// Invalid validator set deserialization + #[error("Invalid validator set")] + InvalidValidatorSet, + /// Invalid proposal field deserialization + #[error("Invalid proposal {0}")] + InvalidProposal(u64), + /// Error during tally + #[error("Error while tallying proposal: {0}")] + Tally(String), +} + +/// Proposal event definition +pub struct ProposalEvent { + /// Proposal event type + pub event_type: String, + /// Proposal event attributes + pub attributes: HashMap, +} + +impl ProposalEvent { + /// Create a proposal event + pub fn new( + event_type: String, + tally: TallyResult, + id: u64, + has_proposal_code: bool, + proposal_code_exit_status: bool, + ) -> Self { + let attributes = HashMap::from([ + ("tally_result".to_string(), tally.to_string()), + ("proposal_id".to_string(), id.to_string()), + ( + "has_proposal_code".to_string(), + (!has_proposal_code as u64).to_string(), + ), + ( + "proposal_code_exit_status".to_string(), + (!proposal_code_exit_status as u64).to_string(), + ), + ]); + Self { + event_type, + attributes, + } + } + + /// Create a new proposal event for rejected proposal + pub fn rejected_proposal_event(proposal_id: u64) -> Self { + ProposalEvent::new( + EventType::Proposal.to_string(), + TallyResult::Rejected, + proposal_id, + false, + false, + ) + } + + /// Create a new proposal event for default proposal + pub fn default_proposal_event( + proposal_id: u64, + has_code: bool, + execution_status: bool, + ) -> Self { + ProposalEvent::new( + EventType::Proposal.to_string(), + TallyResult::Passed, + proposal_id, + has_code, + execution_status, + ) + } + + /// Create a new proposal event for pgf stewards proposal + pub fn pgf_steward_proposal_event(proposal_id: u64, result: bool) -> Self { + ProposalEvent::new( + EventType::Proposal.to_string(), + TallyResult::Passed, + proposal_id, + false, + result, + ) + } + + /// Create a new proposal event for pgf payments proposal + pub fn pgf_payments_proposal_event(proposal_id: u64, result: bool) -> Self { + ProposalEvent::new( + EventType::Proposal.to_string(), + TallyResult::Passed, + proposal_id, + false, + result, + ) + } + + /// Create a new proposal event for eth proposal + pub fn eth_proposal_event(proposal_id: u64, result: bool) -> Self { + ProposalEvent::new( + EventType::Proposal.to_string(), + TallyResult::Passed, + proposal_id, + false, + result, + ) + } +} diff --git a/shared/src/ledger/ibc/vp/mod.rs b/shared/src/ledger/ibc/vp/mod.rs index bab039212a..ec10688066 100644 --- a/shared/src/ledger/ibc/vp/mod.rs +++ b/shared/src/ledger/ibc/vp/mod.rs @@ -298,25 +298,30 @@ mod tests { use super::super::storage::{ ack_key, calc_hash, channel_counter_key, channel_key, client_connections_key, client_counter_key, client_state_key, - client_type_key, client_update_height_key, client_update_timestamp_key, - commitment_key, connection_counter_key, connection_key, - consensus_state_key, ibc_denom_key, next_sequence_ack_key, - next_sequence_recv_key, next_sequence_send_key, receipt_key, + client_update_height_key, client_update_timestamp_key, commitment_key, + connection_counter_key, connection_key, consensus_state_key, + ibc_denom_key, next_sequence_ack_key, next_sequence_recv_key, + next_sequence_send_key, receipt_key, }; use super::{get_dummy_header, *}; use crate::core::ledger::storage::testing::TestWlStorage; - use crate::core::types::address::testing::established_address_1; + use crate::core::types::address::testing::{ + established_address_1, established_address_2, + }; use crate::core::types::address::{nam, InternalAddress}; use crate::core::types::storage::Epoch; use crate::ibc::applications::transfer::acknowledgement::TokenTransferAcknowledgement; use crate::ibc::applications::transfer::coin::PrefixedCoin; use crate::ibc::applications::transfer::denom::TracePrefix; use crate::ibc::applications::transfer::events::{ - AckEvent, DenomTraceEvent, TimeoutEvent, TransferEvent, + AckEvent, DenomTraceEvent, RecvEvent, TimeoutEvent, TransferEvent, }; use crate::ibc::applications::transfer::msgs::transfer::MsgTransfer; use crate::ibc::applications::transfer::packet::PacketData; use crate::ibc::applications::transfer::VERSION; + use crate::ibc::core::events::{ + IbcEvent as RawIbcEvent, MessageEvent, ModuleEvent, + }; use crate::ibc::core::ics02_client::client_state::ClientState; use crate::ibc::core::ics02_client::events::{CreateClient, UpdateClient}; use crate::ibc::core::ics02_client::msgs::create_client::MsgCreateClient; @@ -345,36 +350,30 @@ mod tests { OpenTry as ChanOpenTry, ReceivePacket, SendPacket, TimeoutPacket, WriteAcknowledgement, }; - use crate::ibc::core::ics04_channel::msgs::acknowledgement::{ - Acknowledgement, MsgAcknowledgement, + use crate::ibc::core::ics04_channel::msgs::{ + MsgAcknowledgement, MsgChannelOpenAck, MsgChannelOpenConfirm, + MsgChannelOpenInit, MsgChannelOpenTry, MsgRecvPacket, MsgTimeout, + MsgTimeoutOnClose, + }; + use crate::ibc::core::ics04_channel::packet::{ + Acknowledgement, Packet, Sequence, }; - use crate::ibc::core::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; - use crate::ibc::core::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; - use crate::ibc::core::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; - use crate::ibc::core::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; - use crate::ibc::core::ics04_channel::msgs::recv_packet::MsgRecvPacket; - use crate::ibc::core::ics04_channel::msgs::timeout::MsgTimeout; - use crate::ibc::core::ics04_channel::msgs::timeout_on_close::MsgTimeoutOnClose; - use crate::ibc::core::ics04_channel::packet::{Packet, Sequence}; use crate::ibc::core::ics04_channel::timeout::TimeoutHeight; use crate::ibc::core::ics04_channel::Version as ChanVersion; use crate::ibc::core::ics23_commitment::commitment::{ CommitmentPrefix, CommitmentProofBytes, }; use crate::ibc::core::ics24_host::identifier::{ - ChannelId, ClientId, ConnectionId, PortChannelId, PortId, + ChannelId, ClientId, ConnectionId, PortId, }; - use crate::ibc::events::{IbcEvent as RawIbcEvent, ModuleEvent}; + use crate::ibc::core::timestamp::Timestamp; + use crate::ibc::core::Msg; use crate::ibc::mock::client_state::{ client_type, MockClientState, MOCK_CLIENT_TYPE, }; use crate::ibc::mock::consensus_state::MockConsensusState; use crate::ibc::mock::header::MockHeader; - use crate::ibc::signer::Signer; - use crate::ibc::timestamp::Timestamp; - use crate::ibc::tx_msg::Msg; use crate::ibc::Height; - use crate::ibc_proto::cosmos::base::v1beta1::Coin; use crate::ibc_proto::google::protobuf::Any; use crate::ibc_proto::ibc::core::connection::v1::MsgConnectionOpenTry as RawMsgConnectionOpenTry; use crate::ibc_proto::protobuf::Protobuf; @@ -447,12 +446,6 @@ mod tests { fn insert_init_client(wl_storage: &mut TestWlStorage) { // insert a mock client type let client_id = get_client_id(); - let client_type_key = client_type_key(&client_id); - let client_type = client_type().as_str().as_bytes().to_vec(); - wl_storage - .write_log - .write(&client_type_key, client_type) - .expect("write failed"); // insert a mock client state let client_state_key = client_state_key(&get_client_id()); let height = Height::new(0, 1).unwrap(); @@ -461,8 +454,7 @@ mod tests { timestamp: Timestamp::now(), }; let client_state = MockClientState::new(header); - let bytes = Protobuf::::encode_vec(&client_state) - .expect("encoding failed"); + let bytes = Protobuf::::encode_vec(&client_state); wl_storage .write_log .write(&client_state_key, bytes) @@ -470,8 +462,7 @@ mod tests { // insert a mock consensus state let consensus_key = consensus_state_key(&client_id, height); let consensus_state = MockConsensusState::new(header); - let bytes = Protobuf::::encode_vec(&consensus_state) - .expect("encoding failed"); + let bytes = Protobuf::::encode_vec(&consensus_state); wl_storage .write_log .write(&consensus_key, bytes) @@ -499,10 +490,7 @@ mod tests { Height::new(0, host_height.0).expect("invalid height"); wl_storage .write_log - .write( - &client_update_height_key, - host_height.encode_vec().expect("encoding failed"), - ) + .write(&client_update_height_key, host_height.encode_vec()) .expect("write failed"); wl_storage.write_log.commit_tx(); } @@ -511,13 +499,6 @@ mod tests { ConnectionId::new(0) } - fn get_port_channel_id() -> PortChannelId { - PortChannelId { - port_id: get_port_id(), - channel_id: get_channel_id(), - } - } - fn get_port_id() -> PortId { PortId::transfer() } @@ -534,6 +515,7 @@ mod tests { vec![ConnVersion::default()], Duration::new(0, 0), ) + .unwrap() } fn get_conn_counterparty() -> ConnCounterparty { @@ -557,6 +539,7 @@ mod tests { vec![get_connection_id()], ChanVersion::new(VERSION.to_string()), ) + .unwrap() } fn get_channel_counterparty() -> ChanCounterparty { @@ -603,14 +586,7 @@ mod tests { sequence: Sequence, counterparty: &ChanCounterparty, ) -> Packet { - let coin: PrefixedCoin = - msg.token.clone().try_into().expect("invalid token"); - let packet_data = PacketData { - token: coin, - sender: msg.sender.clone(), - receiver: msg.receiver.clone(), - }; - let data = serde_json::to_vec(&packet_data) + let data = serde_json::to_vec(&msg.packet_data) .expect("Encoding PacketData failed"); Packet { @@ -660,27 +636,17 @@ mod tests { timestamp: Timestamp::now(), }; let client_id = get_client_id(); - // client type - let client_type_key = client_type_key(&client_id); - let client_type = client_type(); - let bytes = client_type.as_str().as_bytes().to_vec(); - wl_storage - .write_log - .write(&client_type_key, bytes) - .expect("write failed"); - keys_changed.insert(client_type_key); // message let client_state = MockClientState::new(header); let consensus_state = MockConsensusState::new(header); let msg = MsgCreateClient { client_state: client_state.into(), consensus_state: consensus_state.clone().into(), - signer: Signer::from_str("account0").expect("invalid signer"), + signer: "account0".to_string().into(), }; // client state let client_state_key = client_state_key(&get_client_id()); - let bytes = Protobuf::::encode_vec(&client_state) - .expect("encoding failed"); + let bytes = Protobuf::::encode_vec(&client_state); wl_storage .write_log .write(&client_state_key, bytes) @@ -688,8 +654,7 @@ mod tests { keys_changed.insert(client_state_key); // client consensus let consensus_key = consensus_state_key(&client_id, height); - let bytes = Protobuf::::encode_vec(&consensus_state) - .expect("encoding failed"); + let bytes = Protobuf::::encode_vec(&consensus_state); wl_storage .write_log .write(&consensus_key, bytes) @@ -720,10 +685,7 @@ mod tests { Height::new(0, host_height.0).expect("invalid height"); wl_storage .write_log - .write( - &client_update_height_key, - host_height.encode_vec().expect("encoding failed"), - ) + .write(&client_update_height_key, host_height.encode_vec()) .expect("write failed"); keys_changed.insert(client_update_height_key); // client counter @@ -733,10 +695,10 @@ mod tests { let event = RawIbcEvent::CreateClient(CreateClient::new( client_id, - client_type, + client_type(), client_state.latest_height(), )); - let message_event = RawIbcEvent::Message(event.event_type()); + let message_event = RawIbcEvent::Message(MessageEvent::Client); wl_storage .write_log .emit_ibc_event(message_event.try_into().unwrap()); @@ -753,7 +715,7 @@ mod tests { wasm::compilation_cache::common::testing::cache(); let verifiers = BTreeSet::new(); - let mut outer_tx = Tx::new(TxType::Raw); + let mut outer_tx = Tx::from_type(TxType::Raw); outer_tx.header.chain_id = wl_storage.storage.chain_id.clone(); outer_tx.set_code(Code::new(tx_code)); outer_tx.set_data(Data::new(tx_data)); @@ -803,23 +765,22 @@ mod tests { height, timestamp: Timestamp::now(), }; - let client_id = get_client_id(); - // insert only client type - let client_type_key = client_type_key(&client_id); - let client_type = client_type(); - let bytes = client_type.as_str().as_bytes().to_vec(); + // insert only client state + let client_state = MockClientState::new(header); + let client_state_key = client_state_key(&get_client_id()); + let bytes = Protobuf::::encode_vec(&client_state); wl_storage .write_log - .write(&client_type_key, bytes) + .write(&client_state_key, bytes) .expect("write failed"); - keys_changed.insert(client_type_key); + keys_changed.insert(client_state_key); let client_state = MockClientState::new(header); let consensus_state = MockConsensusState::new(header); // make a correct message let msg = MsgCreateClient { client_state: client_state.into(), consensus_state: consensus_state.into(), - signer: Signer::from_str("account0").expect("invalid signer"), + signer: "account0".to_string().into(), }; let tx_index = TxIndex::default(); @@ -827,14 +788,10 @@ 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 mut tx = Tx::new(wl_storage.storage.chain_id.clone(), None); + tx.add_code(tx_code) + .add_serialized_data(tx_data) + .sign_wrapper(keypair_1()); let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = @@ -891,12 +848,11 @@ mod tests { let msg = MsgUpdateClient { client_id: client_id.clone(), header: header.into(), - signer: Signer::from_str("account0").expect("invalid signer"), + signer: "account0".to_string().into(), }; // client state let client_state = MockClientState::new(header); - let bytes = Protobuf::::encode_vec(&client_state) - .expect("encoding failed"); + let bytes = Protobuf::::encode_vec(&client_state); wl_storage .write_log .write(&client_state_key, bytes) @@ -905,8 +861,7 @@ mod tests { // consensus state let consensus_key = consensus_state_key(&client_id, height); let consensus_state = MockConsensusState::new(header); - let bytes = Protobuf::::encode_vec(&consensus_state) - .expect("encoding failed"); + let bytes = Protobuf::::encode_vec(&consensus_state); wl_storage .write_log .write(&consensus_key, bytes) @@ -937,10 +892,7 @@ mod tests { Height::new(0, host_height.0).expect("invalid height"); wl_storage .write_log - .write( - &client_update_height_key, - host_height.encode_vec().expect("encoding failed"), - ) + .write(&client_update_height_key, host_height.encode_vec()) .expect("write failed"); keys_changed.insert(client_update_height_key); // event @@ -952,7 +904,7 @@ mod tests { vec![consensus_height], header.into(), )); - let message_event = RawIbcEvent::Message(event.event_type()); + let message_event = RawIbcEvent::Message(MessageEvent::Client); wl_storage .write_log .emit_ibc_event(message_event.try_into().unwrap()); @@ -965,14 +917,10 @@ 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 mut tx = Tx::new(wl_storage.storage.chain_id.clone(), None); + tx.add_code(tx_code) + .add_serialized_data(tx_data) + .sign_wrapper(keypair_1()); let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = @@ -1023,7 +971,7 @@ mod tests { counterparty, version: Some(ConnVersion::default()), delay_period: Duration::new(100, 0), - signer: Signer::from_str("account0").expect("invalid signer"), + signer: "account0".to_string().into(), }; // insert an INIT connection @@ -1035,8 +983,9 @@ mod tests { msg.counterparty.clone(), vec![msg.version.clone().unwrap()], msg.delay_period, - ); - let bytes = conn.encode_vec().expect("encoding failed"); + ) + .expect("invalid connection"); + let bytes = conn.encode_vec(); wl_storage .write_log .write(&conn_key, bytes) @@ -1061,7 +1010,7 @@ mod tests { msg.client_id_on_a.clone(), msg.counterparty.client_id().clone(), )); - let message_event = RawIbcEvent::Message(event.event_type()); + let message_event = RawIbcEvent::Message(MessageEvent::Connection); wl_storage .write_log .emit_ibc_event(message_event.try_into().unwrap()); @@ -1073,7 +1022,7 @@ mod tests { let tx_code = vec![]; let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut outer_tx = Tx::new(TxType::Raw); + let mut outer_tx = Tx::from_type(TxType::Raw); outer_tx.header.chain_id = wl_storage.storage.chain_id.clone(); outer_tx.set_code(Code::new(tx_code)); outer_tx.set_data(Data::new(tx_data)); @@ -1130,7 +1079,7 @@ mod tests { counterparty, version: Some(ConnVersion::default()), delay_period: Duration::new(100, 0), - signer: Signer::from_str("account0").expect("invalid signer"), + signer: "account0".to_string().into(), }; // insert an Init connection @@ -1142,8 +1091,9 @@ mod tests { msg.counterparty.clone(), vec![msg.version.clone().unwrap()], msg.delay_period, - ); - let bytes = conn.encode_vec().expect("encoding failed"); + ) + .expect("invalid connection"); + let bytes = conn.encode_vec(); wl_storage .write_log .write(&conn_key, bytes) @@ -1169,14 +1119,10 @@ 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 mut tx = Tx::new(wl_storage.storage.chain_id.clone(), None); + tx.add_code(tx_code) + .add_serialized_data(tx_data) + .sign_wrapper(keypair_1()); let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = @@ -1258,8 +1204,9 @@ mod tests { msg.counterparty.clone(), msg.versions_on_a.clone(), msg.delay_period, - ); - let bytes = conn.encode_vec().expect("encoding failed"); + ) + .expect("invalid connection"); + let bytes = conn.encode_vec(); wl_storage .write_log .write(&conn_key, bytes) @@ -1285,7 +1232,7 @@ mod tests { msg.counterparty.connection_id().cloned().unwrap(), msg.counterparty.client_id().clone(), )); - let message_event = RawIbcEvent::Message(event.event_type()); + let message_event = RawIbcEvent::Message(MessageEvent::Connection); wl_storage .write_log .emit_ibc_event(message_event.try_into().unwrap()); @@ -1297,14 +1244,12 @@ 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 mut tx = Tx::new(wl_storage.storage.chain_id.clone(), None); + tx.add_code(tx_code) + .add_serialized_data(tx_data) + .sign_wrapper(keypair_1()); + let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = wasm::compilation_cache::common::testing::cache(); @@ -1338,7 +1283,7 @@ mod tests { // insert an Init connection let conn_key = connection_key(&get_connection_id()); let conn = get_connection(ConnState::Init); - let bytes = conn.encode_vec().expect("encoding failed"); + let bytes = conn.encode_vec(); wl_storage .write_log .write(&conn_key, bytes) @@ -1357,7 +1302,7 @@ mod tests { // update the connection to Open let conn = get_connection(ConnState::Open); - let bytes = conn.encode_vec().expect("encoding failed"); + let bytes = conn.encode_vec(); wl_storage .write_log .write(&conn_key, bytes) @@ -1384,7 +1329,7 @@ mod tests { proofs_height_on_b: proof_height, consensus_height_of_a_on_b: client_state.latest_height(), version: ConnVersion::default(), - signer: Signer::from_str("account0").expect("invalid signer"), + signer: "account0".to_string().into(), }; // event let event = RawIbcEvent::OpenAckConnection(ConnOpenAck::new( @@ -1393,7 +1338,7 @@ mod tests { msg.conn_id_on_b.clone(), counterparty.client_id().clone(), )); - let message_event = RawIbcEvent::Message(event.event_type()); + let message_event = RawIbcEvent::Message(MessageEvent::Connection); wl_storage .write_log .emit_ibc_event(message_event.try_into().unwrap()); @@ -1405,7 +1350,7 @@ mod tests { let tx_index = TxIndex::default(); let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut outer_tx = Tx::new(TxType::Raw); + let mut outer_tx = Tx::from_type(TxType::Raw); outer_tx.header.chain_id = wl_storage.storage.chain_id.clone(); outer_tx.set_code(Code::new(tx_code)); outer_tx.set_data(Data::new(tx_data)); @@ -1445,7 +1390,7 @@ mod tests { // insert a TryOpen connection let conn_key = connection_key(&get_connection_id()); let conn = get_connection(ConnState::TryOpen); - let bytes = conn.encode_vec().expect("encoding failed"); + let bytes = conn.encode_vec(); wl_storage .write_log .write(&conn_key, bytes) @@ -1455,7 +1400,7 @@ mod tests { // update the connection to Open let conn = get_connection(ConnState::Open); - let bytes = conn.encode_vec().expect("encoding failed"); + let bytes = conn.encode_vec(); wl_storage .write_log .write(&conn_key, bytes) @@ -1468,7 +1413,7 @@ mod tests { conn_id_on_b: get_connection_id(), proof_conn_end_on_a: dummy_proof(), proof_height_on_a: proof_height, - signer: Signer::from_str("account0").expect("invalid signer"), + signer: "account0".to_string().into(), }; // event let counterparty = get_conn_counterparty(); @@ -1478,7 +1423,7 @@ mod tests { counterparty.connection_id().cloned().unwrap(), counterparty.client_id().clone(), )); - let message_event = RawIbcEvent::Message(event.event_type()); + let message_event = RawIbcEvent::Message(MessageEvent::Connection); wl_storage .write_log .emit_ibc_event(message_event.try_into().unwrap()); @@ -1490,7 +1435,7 @@ mod tests { let tx_index = TxIndex::default(); let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut outer_tx = Tx::new(TxType::Raw); + let mut outer_tx = Tx::from_type(TxType::Raw); outer_tx.header.chain_id = wl_storage.storage.chain_id.clone(); outer_tx.set_code(Code::new(tx_code)); outer_tx.set_data(Data::new(tx_data)); @@ -1531,7 +1476,7 @@ mod tests { let conn_id = get_connection_id(); let conn_key = connection_key(&conn_id); let conn = get_connection(ConnState::Open); - let bytes = conn.encode_vec().expect("encoding failed"); + let bytes = conn.encode_vec(); wl_storage .write_log .write(&conn_key, bytes) @@ -1554,12 +1499,12 @@ mod tests { connection_hops_on_a: vec![conn_id.clone()], port_id_on_b: get_port_id(), ordering: Order::Unordered, - signer: Signer::from_str("account0").expect("invalid signer"), + signer: "account0".to_string().into(), version_proposal: ChanVersion::new(VERSION.to_string()), }; // insert an Init channel - let channel_key = channel_key(&get_port_channel_id()); + let channel_key = channel_key(&get_port_id(), &get_channel_id()); let mut counterparty = get_channel_counterparty(); counterparty.channel_id = None; let channel = ChannelEnd::new( @@ -1568,8 +1513,9 @@ mod tests { counterparty.clone(), msg.connection_hops_on_a.clone(), msg.version_proposal.clone(), - ); - let bytes = channel.encode_vec().expect("encoding failed"); + ) + .unwrap(); + let bytes = channel.encode_vec(); wl_storage .write_log .write(&channel_key, bytes) @@ -1580,15 +1526,15 @@ mod tests { increment_counter(&mut wl_storage, &chan_counter_key); keys_changed.insert(chan_counter_key); // sequences - let port_channel_id = - PortChannelId::new(get_channel_id(), msg.port_id_on_a.clone()); - let send_key = next_sequence_send_key(&port_channel_id); + let channel_id = get_channel_id(); + let port_id = msg.port_id_on_a.clone(); + let send_key = next_sequence_send_key(&port_id, &channel_id); increment_counter(&mut wl_storage, &send_key); keys_changed.insert(send_key); - let recv_key = next_sequence_recv_key(&port_channel_id); + let recv_key = next_sequence_recv_key(&port_id, &channel_id); increment_counter(&mut wl_storage, &recv_key); keys_changed.insert(recv_key); - let ack_key = next_sequence_ack_key(&port_channel_id); + let ack_key = next_sequence_ack_key(&port_id, &channel_id); increment_counter(&mut wl_storage, &ack_key); keys_changed.insert(ack_key); // event @@ -1599,7 +1545,7 @@ mod tests { conn_id, msg.version_proposal.clone(), )); - let message_event = RawIbcEvent::Message(event.event_type()); + let message_event = RawIbcEvent::Message(MessageEvent::Channel); wl_storage .write_log .emit_ibc_event(message_event.try_into().unwrap()); @@ -1611,7 +1557,7 @@ mod tests { let tx_code = vec![]; let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut outer_tx = Tx::new(TxType::Raw); + let mut outer_tx = Tx::from_type(TxType::Raw); outer_tx.header.chain_id = wl_storage.storage.chain_id.clone(); outer_tx.set_code(Code::new(tx_code)); outer_tx.set_data(Data::new(tx_data)); @@ -1651,7 +1597,7 @@ mod tests { // insert an open connection let conn_key = connection_key(&get_connection_id()); let conn = get_connection(ConnState::Open); - let bytes = conn.encode_vec().expect("encoding failed"); + let bytes = conn.encode_vec(); wl_storage .write_log .write(&conn_key, bytes) @@ -1682,15 +1628,14 @@ mod tests { proof_chan_end_on_a: dummy_proof(), proof_height_on_a: proof_height, ordering: Order::Unordered, - signer: Signer::from_str("account0").expect("invalid signer"), - previous_channel_id: ChannelId::default().to_string(), + signer: "account0".to_string().into(), version_proposal: ChanVersion::default(), }; // insert a TryOpen channel - let channel_key = channel_key(&get_port_channel_id()); + let channel_key = channel_key(&get_port_id(), &get_channel_id()); let channel = get_channel(ChanState::TryOpen, Order::Unordered); - let bytes = channel.encode_vec().expect("encoding failed"); + let bytes = channel.encode_vec(); wl_storage .write_log .write(&channel_key, bytes) @@ -1701,15 +1646,15 @@ mod tests { increment_counter(&mut wl_storage, &chan_counter_key); keys_changed.insert(chan_counter_key); // sequences - let port_channel_id = - PortChannelId::new(get_channel_id(), msg.port_id_on_a.clone()); - let send_key = next_sequence_send_key(&port_channel_id); + let channel_id = get_channel_id(); + let port_id = msg.port_id_on_a.clone(); + let send_key = next_sequence_send_key(&port_id, &channel_id); increment_counter(&mut wl_storage, &send_key); keys_changed.insert(send_key); - let recv_key = next_sequence_recv_key(&port_channel_id); + let recv_key = next_sequence_recv_key(&port_id, &channel_id); increment_counter(&mut wl_storage, &recv_key); keys_changed.insert(recv_key); - let ack_key = next_sequence_ack_key(&port_channel_id); + let ack_key = next_sequence_ack_key(&port_id, &channel_id); increment_counter(&mut wl_storage, &ack_key); keys_changed.insert(ack_key); // event @@ -1721,7 +1666,7 @@ mod tests { conn_id, msg.version_supported_on_a.clone(), )); - let message_event = RawIbcEvent::Message(event.event_type()); + let message_event = RawIbcEvent::Message(MessageEvent::Channel); wl_storage .write_log .emit_ibc_event(message_event.try_into().unwrap()); @@ -1733,7 +1678,7 @@ mod tests { let tx_code = vec![]; let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut outer_tx = Tx::new(TxType::Raw); + let mut outer_tx = Tx::from_type(TxType::Raw); outer_tx.header.chain_id = wl_storage.storage.chain_id.clone(); outer_tx.set_code(Code::new(tx_code)); outer_tx.set_data(Data::new(tx_data)); @@ -1773,15 +1718,15 @@ mod tests { // insert an open connection let conn_key = connection_key(&get_connection_id()); let conn = get_connection(ConnState::Open); - let bytes = conn.encode_vec().expect("encoding failed"); + let bytes = conn.encode_vec(); wl_storage .write_log .write(&conn_key, bytes) .expect("write failed"); // insert an Init channel - let channel_key = channel_key(&get_port_channel_id()); + let channel_key = channel_key(&get_port_id(), &get_channel_id()); let channel = get_channel(ChanState::Init, Order::Unordered); - let bytes = channel.encode_vec().expect("encoding failed"); + let bytes = channel.encode_vec(); wl_storage .write_log .write(&channel_key, bytes) @@ -1808,12 +1753,12 @@ mod tests { version_on_b: ChanVersion::new(VERSION.to_string()), proof_chan_end_on_b: dummy_proof(), proof_height_on_b: proof_height, - signer: Signer::from_str("account0").expect("invalid signer"), + signer: "account0".to_string().into(), }; // update the channel to Open let channel = get_channel(ChanState::Open, Order::Unordered); - let bytes = channel.encode_vec().expect("encoding failed"); + let bytes = channel.encode_vec(); wl_storage .write_log .write(&channel_key, bytes) @@ -1827,7 +1772,7 @@ mod tests { counterparty.channel_id().cloned().unwrap(), get_connection_id(), )); - let message_event = RawIbcEvent::Message(event.event_type()); + let message_event = RawIbcEvent::Message(MessageEvent::Channel); wl_storage .write_log .emit_ibc_event(message_event.try_into().unwrap()); @@ -1839,7 +1784,7 @@ mod tests { let tx_code = vec![]; let mut tx_data = vec![]; msg.to_any().encode(&mut tx_data).expect("encoding failed"); - let mut outer_tx = Tx::new(TxType::Raw); + let mut outer_tx = Tx::from_type(TxType::Raw); outer_tx.header.chain_id = wl_storage.storage.chain_id.clone(); outer_tx.set_code(Code::new(tx_code)); outer_tx.set_data(Data::new(tx_data)); @@ -1879,15 +1824,15 @@ mod tests { // insert an open connection let conn_key = connection_key(&get_connection_id()); let conn = get_connection(ConnState::Open); - let bytes = conn.encode_vec().expect("encoding failed"); + let bytes = conn.encode_vec(); wl_storage .write_log .write(&conn_key, bytes) .expect("write failed"); // insert a TryOpen channel - let channel_key = channel_key(&get_port_channel_id()); + let channel_key = channel_key(&get_port_id(), &get_channel_id()); let channel = get_channel(ChanState::TryOpen, Order::Ordered); - let bytes = channel.encode_vec().expect("encoding failed"); + let bytes = channel.encode_vec(); wl_storage .write_log .write(&channel_key, bytes) @@ -1911,12 +1856,12 @@ mod tests { chan_id_on_b: get_channel_id(), proof_chan_end_on_a: dummy_proof(), proof_height_on_a: proof_height, - signer: Signer::from_str("account0").expect("invalid signer"), + signer: "account0".to_string().into(), }; // update the channel to Open let channel = get_channel(ChanState::Open, Order::Ordered); - let bytes = channel.encode_vec().expect("encoding failed"); + let bytes = channel.encode_vec(); wl_storage .write_log .write(&channel_key, bytes) @@ -1931,7 +1876,7 @@ mod tests { counterparty.channel_id().cloned().unwrap(), get_connection_id(), )); - let message_event = RawIbcEvent::Message(event.event_type()); + let message_event = RawIbcEvent::Message(MessageEvent::Channel); wl_storage .write_log .emit_ibc_event(message_event.try_into().unwrap()); @@ -1943,14 +1888,12 @@ 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 mut tx = Tx::new(wl_storage.storage.chain_id.clone(), None); + tx.add_code(tx_code) + .add_serialized_data(tx_data) + .sign_wrapper(keypair_1()); + let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = wasm::compilation_cache::common::testing::cache(); @@ -1986,15 +1929,15 @@ mod tests { // insert an open connection let conn_key = connection_key(&get_connection_id()); let conn = get_connection(ConnState::Open); - let bytes = conn.encode_vec().expect("encoding failed"); + let bytes = conn.encode_vec(); wl_storage .write_log .write(&conn_key, bytes) .expect("write failed"); // insert an Open channel - let channel_key = channel_key(&get_port_channel_id()); + let channel_key = channel_key(&get_port_id(), &get_channel_id()); let channel = get_channel(ChanState::Open, Order::Unordered); - let bytes = channel.encode_vec().expect("encoding failed"); + let bytes = channel.encode_vec(); wl_storage .write_log .write(&channel_key, bytes) @@ -2023,19 +1966,21 @@ mod tests { let msg = MsgTransfer { port_id_on_a: get_port_id(), chan_id_on_a: get_channel_id(), - token: Coin { - denom: nam().to_string(), - amount: 100u64.to_string(), + packet_data: PacketData { + token: PrefixedCoin { + denom: nam().to_string().parse().unwrap(), + amount: 100u64.into(), + }, + sender: sender.to_string().into(), + receiver: "receiver".to_string().into(), + memo: "memo".to_string().into(), }, - sender: Signer::from_str(&sender.to_string()) - .expect("invalid signer"), - receiver: Signer::from_str("receiver").expect("invalid signer"), - timeout_height_on_b: TimeoutHeight::Never, + timeout_height_on_b: TimeoutHeight::At(Height::new(0, 10).unwrap()), timeout_timestamp_on_b: Timestamp::none(), }; // the sequence send - let seq_key = next_sequence_send_key(&get_port_channel_id()); + let seq_key = next_sequence_send_key(&get_port_id(), &get_channel_id()); let sequence = get_next_seq(&wl_storage, &seq_key); wl_storage .write_log @@ -2056,10 +2001,13 @@ mod tests { keys_changed.insert(commitment_key); // event let transfer_event = TransferEvent { - sender: msg.sender.clone(), - receiver: msg.receiver.clone(), + sender: msg.packet_data.sender.clone(), + receiver: msg.packet_data.receiver.clone(), + amount: msg.packet_data.token.amount, + denom: msg.packet_data.token.denom.clone(), + memo: msg.packet_data.memo.clone(), }; - let event = RawIbcEvent::AppModule(ModuleEvent::from(transfer_event)); + let event = RawIbcEvent::Module(ModuleEvent::from(transfer_event)); wl_storage .write_log .emit_ibc_event(event.try_into().unwrap()); @@ -2068,7 +2016,7 @@ mod tests { Order::Unordered, get_connection_id(), )); - let message_event = RawIbcEvent::Message(event.event_type()); + let message_event = RawIbcEvent::Message(MessageEvent::Channel); wl_storage .write_log .emit_ibc_event(message_event.try_into().unwrap()); @@ -2080,14 +2028,12 @@ 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 mut tx = Tx::new(wl_storage.storage.chain_id.clone(), None); + tx.add_code(tx_code) + .add_serialized_data(tx_data) + .sign_wrapper(keypair_1()); + let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = wasm::compilation_cache::common::testing::cache(); @@ -2120,15 +2066,15 @@ mod tests { // insert an open connection let conn_key = connection_key(&get_connection_id()); let conn = get_connection(ConnState::Open); - let bytes = conn.encode_vec().expect("encoding failed"); + let bytes = conn.encode_vec(); wl_storage .write_log .write(&conn_key, bytes) .expect("write failed"); // insert an open channel - let channel_key = channel_key(&get_port_channel_id()); + let channel_key = channel_key(&get_port_id(), &get_channel_id()); let channel = get_channel(ChanState::Open, Order::Unordered); - let bytes = channel.encode_vec().expect("encoding failed"); + let bytes = channel.encode_vec(); wl_storage .write_log .write(&channel_key, bytes) @@ -2146,18 +2092,21 @@ mod tests { .unwrap(); // prepare data - let receiver = established_address_1(); + let sender = established_address_1(); + let receiver = established_address_2(); let transfer_msg = MsgTransfer { port_id_on_a: get_port_id(), chan_id_on_a: get_channel_id(), - token: Coin { - denom: nam().to_string(), - amount: 100u64.to_string(), + packet_data: PacketData { + token: PrefixedCoin { + denom: nam().to_string().parse().unwrap(), + amount: 100u64.into(), + }, + sender: sender.to_string().into(), + receiver: receiver.to_string().into(), + memo: "memo".to_string().into(), }, - sender: Signer::from_str("sender").expect("invalid signer"), - receiver: Signer::from_str(&receiver.to_string()) - .expect("invalid signer"), - timeout_height_on_b: TimeoutHeight::Never, + timeout_height_on_b: TimeoutHeight::At(Height::new(0, 10).unwrap()), timeout_timestamp_on_b: Timestamp::none(), }; let counterparty = get_channel_counterparty(); @@ -2171,7 +2120,7 @@ mod tests { packet: packet.clone(), proof_commitment_on_a: dummy_proof(), proof_height_on_a: Height::new(0, 1).unwrap(), - signer: Signer::from_str("account0").expect("invalid signer"), + signer: "account0".to_string().into(), }; // the sequence send @@ -2201,8 +2150,7 @@ mod tests { .expect("write failed"); keys_changed.insert(ack_key); // denom - let mut coin: PrefixedCoin = - transfer_msg.token.try_into().expect("invalid token"); + let mut coin = transfer_msg.packet_data.token; coin.denom.add_trace_prefix(TracePrefix::new( packet.port_id_on_b.clone(), packet.chan_id_on_b.clone(), @@ -2216,12 +2164,23 @@ mod tests { .expect("write failed"); keys_changed.insert(denom_key); // event + let recv_event = RecvEvent { + sender: sender.to_string().into(), + receiver: receiver.to_string().into(), + denom: nam().to_string().parse().unwrap(), + amount: 100u64.into(), + memo: "memo".to_string().into(), + success: true, + }; + let event = RawIbcEvent::Module(ModuleEvent::from(recv_event)); + wl_storage + .write_log + .emit_ibc_event(event.try_into().unwrap()); let denom_trace_event = DenomTraceEvent { trace_hash: Some(trace_hash), denom: coin.denom, }; - let event = - RawIbcEvent::AppModule(ModuleEvent::from(denom_trace_event)); + let event = RawIbcEvent::Module(ModuleEvent::from(denom_trace_event)); wl_storage .write_log .emit_ibc_event(event.try_into().unwrap()); @@ -2230,7 +2189,7 @@ mod tests { Order::Unordered, get_connection_id(), )); - let message_event = RawIbcEvent::Message(event.event_type()); + let message_event = RawIbcEvent::Message(MessageEvent::Channel); wl_storage .write_log .emit_ibc_event(message_event.try_into().unwrap()); @@ -2243,7 +2202,7 @@ mod tests { acknowledgement, get_connection_id(), )); - let message_event = RawIbcEvent::Message(event.event_type()); + let message_event = RawIbcEvent::Message(MessageEvent::Channel); wl_storage .write_log .emit_ibc_event(message_event.try_into().unwrap()); @@ -2255,14 +2214,12 @@ 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 mut tx = Tx::new(wl_storage.storage.chain_id.clone(), None); + tx.add_code(tx_code) + .add_serialized_data(tx_data) + .sign_wrapper(keypair_1()); + let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = wasm::compilation_cache::common::testing::cache(); @@ -2295,15 +2252,15 @@ mod tests { // insert an open connection let conn_key = connection_key(&get_connection_id()); let conn = get_connection(ConnState::Open); - let bytes = conn.encode_vec().expect("encoding failed"); + let bytes = conn.encode_vec(); wl_storage .write_log .write(&conn_key, bytes) .expect("write failed"); // insert an Open channel - let channel_key = channel_key(&get_port_channel_id()); + let channel_key = channel_key(&get_port_id(), &get_channel_id()); let channel = get_channel(ChanState::Open, Order::Unordered); - let bytes = channel.encode_vec().expect("encoding failed"); + let bytes = channel.encode_vec(); wl_storage .write_log .write(&channel_key, bytes) @@ -2313,14 +2270,16 @@ mod tests { let transfer_msg = MsgTransfer { port_id_on_a: get_port_id(), chan_id_on_a: get_channel_id(), - token: Coin { - denom: nam().to_string(), - amount: 100u64.to_string(), + packet_data: PacketData { + token: PrefixedCoin { + denom: nam().to_string().parse().unwrap(), + amount: 100u64.into(), + }, + sender: sender.to_string().into(), + receiver: "receiver".to_string().into(), + memo: "memo".to_string().into(), }, - sender: Signer::from_str(&sender.to_string()) - .expect("invalid signer"), - receiver: Signer::from_str("receiver").expect("invalid signer"), - timeout_height_on_b: TimeoutHeight::Never, + timeout_height_on_b: TimeoutHeight::At(Height::new(0, 10).unwrap()), timeout_timestamp_on_b: Timestamp::none(), }; let sequence = 1.into(); @@ -2354,13 +2313,12 @@ mod tests { // prepare data let transfer_ack = TokenTransferAcknowledgement::success(); - let acknowledgement = Acknowledgement::from(transfer_ack.clone()); let msg = MsgAcknowledgement { packet: packet.clone(), - acknowledgement, + acknowledgement: transfer_ack.clone().into(), proof_acked_on_b: dummy_proof(), proof_height_on_b: Height::new(0, 1).unwrap(), - signer: Signer::from_str("account0").expect("invalid signer"), + signer: "account0".to_string().into(), }; // delete the commitment @@ -2373,12 +2331,14 @@ mod tests { let data = serde_json::from_slice::(&packet.data) .expect("decoding packet data failed"); let ack_event = AckEvent { + sender: data.sender, receiver: data.receiver, denom: data.token.denom, amount: data.token.amount, + memo: data.memo, acknowledgement: transfer_ack, }; - let event = RawIbcEvent::AppModule(ModuleEvent::from(ack_event)); + let event = RawIbcEvent::Module(ModuleEvent::from(ack_event)); wl_storage .write_log .emit_ibc_event(event.try_into().unwrap()); @@ -2387,7 +2347,7 @@ mod tests { Order::Unordered, get_connection_id(), )); - let message_event = RawIbcEvent::Message(event.event_type()); + let message_event = RawIbcEvent::Message(MessageEvent::Channel); wl_storage .write_log .emit_ibc_event(message_event.try_into().unwrap()); @@ -2399,14 +2359,12 @@ 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 mut tx = Tx::new(wl_storage.storage.chain_id.clone(), None); + tx.add_code(tx_code) + .add_serialized_data(tx_data) + .sign_wrapper(keypair_1()); + let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = wasm::compilation_cache::common::testing::cache(); @@ -2439,15 +2397,15 @@ mod tests { // insert an open connection let conn_key = connection_key(&get_connection_id()); let conn = get_connection(ConnState::Open); - let bytes = conn.encode_vec().expect("encoding failed"); + let bytes = conn.encode_vec(); wl_storage .write_log .write(&conn_key, bytes) .expect("write failed"); // insert an Open channel - let channel_key = channel_key(&get_port_channel_id()); + let channel_key = channel_key(&get_port_id(), &get_channel_id()); let channel = get_channel(ChanState::Open, Order::Unordered); - let bytes = channel.encode_vec().expect("encoding failed"); + let bytes = channel.encode_vec(); wl_storage .write_log .write(&channel_key, bytes) @@ -2461,17 +2419,18 @@ mod tests { .write(&balance_key, amount.try_to_vec().unwrap()) .expect("write failed"); // commitment - let sender = established_address_1(); let transfer_msg = MsgTransfer { port_id_on_a: get_port_id(), chan_id_on_a: get_channel_id(), - token: Coin { - denom: nam().to_string(), - amount: 100u64.to_string(), + packet_data: PacketData { + token: PrefixedCoin { + denom: nam().to_string().parse().unwrap(), + amount: 100u64.into(), + }, + sender: established_address_1().to_string().into(), + receiver: "receiver".to_string().into(), + memo: "memo".to_string().into(), }, - sender: Signer::from_str(&sender.to_string()) - .expect("invalid signer"), - receiver: Signer::from_str("receiver").expect("invalid signer"), timeout_height_on_b: TimeoutHeight::Never, timeout_timestamp_on_b: (Timestamp::now() - Duration::new(10, 0)) .unwrap(), @@ -2511,7 +2470,7 @@ mod tests { next_seq_recv_on_b: sequence, proof_unreceived_on_b: dummy_proof(), proof_height_on_b: Height::new(0, 1).unwrap(), - signer: Signer::from_str("account0").expect("invalid signer"), + signer: "account0".to_string().into(), }; // delete the commitment @@ -2527,8 +2486,9 @@ mod tests { refund_receiver: data.sender, refund_denom: data.token.denom, refund_amount: data.token.amount, + memo: data.memo, }; - let event = RawIbcEvent::AppModule(ModuleEvent::from(timeout_event)); + let event = RawIbcEvent::Module(ModuleEvent::from(timeout_event)); wl_storage .write_log .emit_ibc_event(event.try_into().unwrap()); @@ -2536,7 +2496,7 @@ mod tests { packet, Order::Unordered, )); - let message_event = RawIbcEvent::Message(event.event_type()); + let message_event = RawIbcEvent::Message(MessageEvent::Channel); wl_storage .write_log .emit_ibc_event(message_event.try_into().unwrap()); @@ -2548,14 +2508,12 @@ 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 mut tx = Tx::new(wl_storage.storage.chain_id.clone(), None); + tx.add_code(tx_code) + .add_serialized_data(tx_data) + .sign_wrapper(keypair_1()); + let gas_meter = VpGasMeter::new(0); let (vp_wasm_cache, _vp_cache_dir) = wasm::compilation_cache::common::testing::cache(); @@ -2588,15 +2546,15 @@ mod tests { // insert an open connection let conn_key = connection_key(&get_connection_id()); let conn = get_connection(ConnState::Open); - let bytes = conn.encode_vec().expect("encoding failed"); + let bytes = conn.encode_vec(); wl_storage .write_log .write(&conn_key, bytes) .expect("write failed"); // insert an Open channel - let channel_key = channel_key(&get_port_channel_id()); + let channel_key = channel_key(&get_port_id(), &get_channel_id()); let channel = get_channel(ChanState::Open, Order::Unordered); - let bytes = channel.encode_vec().expect("encoding failed"); + let bytes = channel.encode_vec(); wl_storage .write_log .write(&channel_key, bytes) @@ -2614,14 +2572,16 @@ mod tests { let transfer_msg = MsgTransfer { port_id_on_a: get_port_id(), chan_id_on_a: get_channel_id(), - token: Coin { - denom: nam().to_string(), - amount: 100u64.to_string(), + packet_data: PacketData { + token: PrefixedCoin { + denom: nam().to_string().parse().unwrap(), + amount: 100u64.into(), + }, + sender: sender.to_string().into(), + receiver: "receiver".to_string().into(), + memo: "memo".to_string().into(), }, - sender: Signer::from_str(&sender.to_string()) - .expect("invalid signer"), - receiver: Signer::from_str("receiver").expect("invalid signer"), - timeout_height_on_b: TimeoutHeight::Never, + timeout_height_on_b: TimeoutHeight::At(Height::new(0, 10).unwrap()), timeout_timestamp_on_b: Timestamp::none(), }; let sequence = 1.into(); @@ -2660,7 +2620,7 @@ mod tests { proof_unreceived_on_b: dummy_proof(), proof_close_on_b: dummy_proof(), proof_height_on_b: Height::new(0, 1).unwrap(), - signer: Signer::from_str("account0").expect("invalid signer"), + signer: "account0".to_string().into(), }; // delete the commitment @@ -2676,8 +2636,9 @@ mod tests { refund_receiver: data.sender, refund_denom: data.token.denom, refund_amount: data.token.amount, + memo: data.memo, }; - let event = RawIbcEvent::AppModule(ModuleEvent::from(timeout_event)); + let event = RawIbcEvent::Module(ModuleEvent::from(timeout_event)); wl_storage .write_log .emit_ibc_event(event.try_into().unwrap()); @@ -2685,7 +2646,7 @@ mod tests { packet, Order::Unordered, )); - let message_event = RawIbcEvent::Message(event.event_type()); + let message_event = RawIbcEvent::Message(MessageEvent::Channel); wl_storage .write_log .emit_ibc_event(message_event.try_into().unwrap()); @@ -2697,14 +2658,12 @@ 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 mut tx = Tx::new(wl_storage.storage.chain_id.clone(), None); + tx.add_code(tx_code) + .add_serialized_data(tx_data) + .sign_wrapper(keypair_1()); + 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/masp.rs b/shared/src/ledger/masp.rs index 8596ceca84..484fb34860 100644 --- a/shared/src/ledger/masp.rs +++ b/shared/src/ledger/masp.rs @@ -1,7 +1,6 @@ //! MASP verification wrappers. -use std::collections::hash_map::Entry; -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::collections::{btree_map, BTreeMap, BTreeSet, HashMap, HashSet}; use std::env; use std::fmt::Debug; #[cfg(feature = "masp-tx-gen")] @@ -81,6 +80,17 @@ use crate::{display_line, edisplay_line}; /// the default OS specific path is used. pub const ENV_VAR_MASP_PARAMS_DIR: &str = "NAMADA_MASP_PARAMS_DIR"; +/// Env var to either "save" proofs into files or to "load" them from +/// files. +pub const ENV_VAR_MASP_TEST_PROOFS: &str = "NAMADA_MASP_TEST_PROOFS"; + +/// Randomness seed for MASP integration tests to build proofs with +/// deterministic rng. +pub const ENV_VAR_MASP_TEST_SEED: &str = "NAMADA_MASP_TEST_SEED"; + +/// A directory to save serialized proofs for tests. +pub const MASP_TEST_PROOFS_DIR: &str = "test_fixtures/masp_proofs"; + /// The network to use for MASP #[cfg(feature = "mainnet")] const NETWORK: MainNetwork = MainNetwork; @@ -95,6 +105,26 @@ pub const OUTPUT_NAME: &str = "masp-output.params"; /// Convert circuit name pub const CONVERT_NAME: &str = "masp-convert.params"; +/// Shielded transfer +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)] +pub struct ShieldedTransfer { + /// Shielded transfer builder + pub builder: Builder<(), (), ExtendedFullViewingKey, ()>, + /// MASP transaction + pub masp_tx: Transaction, + /// Metadata + pub metadata: SaplingMetadata, + /// Epoch in which the transaction was created + pub epoch: Epoch, +} + +#[derive(Clone, Copy, Debug)] +enum LoadOrSaveProofs { + Load, + Save, + Neither, +} + fn load_pvks() -> ( PreparedVerifyingKey, PreparedVerifyingKey, @@ -513,7 +543,7 @@ impl From for Amount { /// Represents the amount used of different conversions pub type Conversions = - HashMap, i128)>; + BTreeMap, i128)>; /// Represents the changes that were made to a list of transparent accounts pub type TransferDelta = HashMap; @@ -533,7 +563,7 @@ pub struct ShieldedContext { /// The commitment tree produced by scanning all transactions up to tx_pos pub tree: CommitmentTree, /// Maps viewing keys to applicable note positions - pub pos_map: HashMap>, + pub pos_map: HashMap>, /// Maps a nullifier to the note position to which it applies pub nf_map: HashMap, /// Maps note positions to their corresponding notes @@ -659,7 +689,7 @@ impl ShieldedContext { ..Default::default() }; for vk in unknown_keys { - tx_ctx.pos_map.entry(vk).or_insert_with(HashSet::new); + tx_ctx.pos_map.entry(vk).or_insert_with(BTreeSet::new); } // Update this unknown shielded context until it is level with self while tx_ctx.last_txidx != self.last_txidx { @@ -933,7 +963,9 @@ impl ShieldedContext { asset_type: AssetType, conversions: &'a mut Conversions, ) { - if let Entry::Vacant(conv_entry) = conversions.entry(asset_type) { + if let btree_map::Entry::Vacant(conv_entry) = + conversions.entry(asset_type) + { // Query for the ID of the last accepted transaction if let Some((addr, denom, ep, conv, path)) = query_conversion(client, asset_type).await @@ -964,7 +996,7 @@ impl ShieldedContext { client, balance, target_epoch, - HashMap::new(), + BTreeMap::new(), ) .await .0; @@ -1147,7 +1179,7 @@ impl ShieldedContext { Conversions, ) { // Establish connection with which to do exchange rate queries - let mut conversions = HashMap::new(); + let mut conversions = BTreeMap::new(); let mut val_acc = Amount::zero(); let mut notes = Vec::new(); // Retrieve the notes that can be spent by this key @@ -1295,7 +1327,7 @@ impl ShieldedContext { client, amount, ep, - HashMap::new(), + BTreeMap::new(), ) .await .0; @@ -1367,16 +1399,17 @@ impl ShieldedContext { args: &args::TxTransfer, shielded_gas: bool, ) -> Result< - Option<( - Builder<(), (), ExtendedFullViewingKey, ()>, - Transaction, - SaplingMetadata, - Epoch, - )>, + Option, builder::Error, > { // No shielded components are needed when neither source nor destination // are shielded + + use std::str::FromStr; + + use rand::rngs::StdRng; + use rand_core::SeedableRng; + let spending_key = args.source.spending_key(); let payment_address = args.target.payment_address(); // No shielded components are needed when neither source nor @@ -1398,8 +1431,27 @@ impl ShieldedContext { // possesion let memo = MemoBytes::empty(); + // Try to get a seed from env var, if any. + let rng = if let Ok(seed) = + env::var(ENV_VAR_MASP_TEST_SEED).map(|seed| { + let exp_str = + format!("Env var {ENV_VAR_MASP_TEST_SEED} must be a u64."); + let parsed_seed: u64 = + FromStr::from_str(&seed).expect(&exp_str); + parsed_seed + }) { + tracing::warn!( + "UNSAFE: Using a seed from {ENV_VAR_MASP_TEST_SEED} env var \ + to build proofs." + ); + StdRng::seed_from_u64(seed) + } else { + StdRng::from_rng(OsRng).unwrap() + }; + // Now we build up the transaction within this object - let mut builder = Builder::::new(NETWORK, 1.into()); + let mut builder = + Builder::::new_with_rng(NETWORK, 1.into(), rng); // break up a transfer into a number of transfers with suitable // denominations @@ -1413,13 +1465,13 @@ impl ShieldedContext { let tx_fee = // If there are shielded inputs if let Some(sk) = spending_key { - let InputAmount::Validated(fee) = args.tx.fee_amount else { + let InputAmount::Validated(fee) = args.tx.gas_amount else { unreachable!("The function `gen_shielded_transfer` is only called by `submit_tx` which validates amounts.") }; // Transaction fees need to match the amount in the wrapper Transfer // when MASP source is used let (_, shielded_fee) = - convert_amount(epoch, &args.tx.fee_token, fee.amount); + convert_amount(epoch, &args.tx.gas_token, fee.amount); let required_amt = if shielded_gas { amount + shielded_fee.clone() } else { @@ -1558,16 +1610,81 @@ impl ShieldedContext { } } - // Build and return the constructed transaction - builder - .clone() - .build( + // To speed up integration tests, we can save and load proofs + let load_or_save = if let Ok(masp_proofs) = + env::var(ENV_VAR_MASP_TEST_PROOFS) + { + let parsed = match masp_proofs.to_ascii_lowercase().as_str() { + "load" => LoadOrSaveProofs::Load, + "save" => LoadOrSaveProofs::Save, + env_var => panic!( + "Unexpected value for {ENV_VAR_MASP_TEST_PROOFS} env var. \ + Expecting \"save\" or \"load\", but got \"{env_var}\"." + ), + }; + if env::var(ENV_VAR_MASP_TEST_SEED).is_err() { + panic!( + "Ensure to set a seed with {ENV_VAR_MASP_TEST_SEED} env \ + var when using {ENV_VAR_MASP_TEST_PROOFS} for \ + deterministic proofs." + ); + } + parsed + } else { + LoadOrSaveProofs::Neither + }; + + let builder_clone = builder.clone().map_builder(WalletMap); + let builder_bytes = BorshSerialize::try_to_vec(&builder_clone).unwrap(); + let builder_hash = + namada_core::types::hash::Hash::sha256(&builder_bytes); + let saved_filepath = env::current_dir() + .unwrap() + // One up from "tests" dir to the root dir + .parent() + .unwrap() + .join(MASP_TEST_PROOFS_DIR) + .join(format!("{builder_hash}.bin")); + + if let LoadOrSaveProofs::Load = load_or_save { + let recommendation = format!( + "Re-run the tests with {ENV_VAR_MASP_TEST_PROOFS}=save to \ + re-generate proofs." + ); + let exp_str = format!( + "Read saved MASP proofs from {}. {recommendation}", + saved_filepath.to_string_lossy() + ); + let loaded_bytes = + tokio::fs::read(&saved_filepath).await.expect(&exp_str); + let exp_str = format!( + "Valid `ShieldedTransfer` bytes in {}. {recommendation}", + saved_filepath.to_string_lossy() + ); + let loaded: ShieldedTransfer = + BorshDeserialize::try_from_slice(&loaded_bytes) + .expect(&exp_str); + Ok(Some(loaded)) + } else { + // Build and return the constructed transaction + let (masp_tx, metadata) = builder.build( &self.utils.local_tx_prover(), &FeeRule::non_standard(tx_fee), - ) - .map(|(tx, metadata)| { - Some((builder.map_builder(WalletMap), tx, metadata, epoch)) - }) + )?; + let built = ShieldedTransfer { + builder: builder_clone, + masp_tx, + metadata, + epoch, + }; + if let LoadOrSaveProofs::Save = load_or_save { + let built_bytes = BorshSerialize::try_to_vec(&built).unwrap(); + tokio::fs::write(&saved_filepath, built_bytes) + .await + .unwrap(); + } + Ok(Some(built)) + } } /// Obtain the known effects of all accepted shielded and transparent diff --git a/shared/src/ledger/mod.rs b/shared/src/ledger/mod.rs index 399f75f800..a5b2a06819 100644 --- a/shared/src/ledger/mod.rs +++ b/shared/src/ledger/mod.rs @@ -3,10 +3,12 @@ pub mod args; pub mod eth_bridge; pub mod events; +pub mod governance; pub mod ibc; pub mod inflation; pub mod masp; pub mod native_vp; +pub mod pgf; pub mod pos; #[cfg(all(feature = "wasm-runtime", feature = "ferveo-tpke"))] pub mod protocol; @@ -20,5 +22,5 @@ pub mod vp_host_fns; pub mod wallet; pub use namada_core::ledger::{ - gas, governance, parameters, replay_protection, storage_api, tx_env, vp_env, + gas, parameters, replay_protection, storage_api, tx_env, vp_env, }; 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 a63b252955..323633b563 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 @@ -355,7 +355,6 @@ 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}; @@ -566,7 +565,7 @@ mod test_bridge_pool_vp { { // setup let mut wl_storage = setup_storage(); - let tx = Tx::new(TxType::Raw); + let tx = Tx::from_type(TxType::Raw); // the transfer to be added to the pool let transfer = PendingTransfer { @@ -622,8 +621,8 @@ 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 mut tx = Tx::new(wl_storage.storage.chain_id.clone(), None); + tx.add_data(transfer); let res = vp.validate_tx(&tx, &keys_changed, &verifiers); match expect { @@ -905,7 +904,7 @@ mod test_bridge_pool_vp { fn test_adding_transfer_twice_fails() { // setup let mut wl_storage = setup_storage(); - let tx = Tx::new(TxType::Raw); + let tx = Tx::from_type(TxType::Raw); // the transfer to be added to the pool let transfer = initial_pool(); @@ -960,8 +959,8 @@ 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 mut tx = Tx::new(wl_storage.storage.chain_id.clone(), None); + tx.add_data(transfer); let res = vp.validate_tx(&tx, &keys_changed, &verifiers); assert!(!res.expect("Test failed")); @@ -973,7 +972,7 @@ mod test_bridge_pool_vp { fn test_zero_gas_fees_rejected() { // setup let mut wl_storage = setup_storage(); - let tx = Tx::new(TxType::Raw); + let tx = Tx::from_type(TxType::Raw); // the transfer to be added to the pool let transfer = PendingTransfer { @@ -1022,8 +1021,8 @@ 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 mut tx = Tx::new(wl_storage.storage.chain_id.clone(), None); + tx.add_data(transfer); let res = vp .validate_tx(&tx, &keys_changed, &verifiers) @@ -1039,7 +1038,7 @@ mod test_bridge_pool_vp { let mut wl_storage = setup_storage(); let eb_account_key = balance_key(&nam(), &Address::Internal(InternalAddress::EthBridge)); - let tx = Tx::new(TxType::Raw); + let tx = Tx::from_type(TxType::Raw); // the transfer to be added to the pool let transfer = PendingTransfer { @@ -1108,8 +1107,8 @@ 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 mut tx = Tx::new(wl_storage.storage.chain_id.clone(), None); + tx.add_data(transfer); let res = vp .validate_tx(&tx, &keys_changed, &verifiers) @@ -1124,7 +1123,7 @@ mod test_bridge_pool_vp { fn test_reject_mint_wnam() { // setup let mut wl_storage = setup_storage(); - let tx = Tx::new(TxType::Raw); + let tx = Tx::from_type(TxType::Raw); let eb_account_key = balance_key(&nam(), &Address::Internal(InternalAddress::EthBridge)); @@ -1195,8 +1194,8 @@ 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 mut tx = Tx::new(wl_storage.storage.chain_id.clone(), None); + tx.add_data(transfer); let res = vp .validate_tx(&tx, &keys_changed, &verifiers) @@ -1232,7 +1231,7 @@ mod test_bridge_pool_vp { ) .expect("Test failed"); wl_storage.write_log.commit_tx(); - let tx = Tx::new(TxType::Raw); + let tx = Tx::from_type(TxType::Raw); // the transfer to be added to the pool let transfer = PendingTransfer { @@ -1309,8 +1308,8 @@ 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 mut tx = Tx::new(wl_storage.storage.chain_id.clone(), None); + tx.add_data(transfer); let res = vp .validate_tx(&tx, &keys_changed, &verifiers) diff --git a/shared/src/ledger/native_vp/ethereum_bridge/vp.rs b/shared/src/ledger/native_vp/ethereum_bridge/vp.rs index 33a828938a..5fd7aa6cd1 100644 --- a/shared/src/ledger/native_vp/ethereum_bridge/vp.rs +++ b/shared/src/ledger/native_vp/ethereum_bridge/vp.rs @@ -588,7 +588,7 @@ mod tests { let verifiers = BTreeSet::from([BRIDGE_POOL_ADDRESS]); // set up the VP - let tx = Tx::new(TxType::Raw); + let tx = Tx::from_type(TxType::Raw); let vp = EthBridge { ctx: setup_ctx( &tx, @@ -638,7 +638,7 @@ mod tests { let verifiers = BTreeSet::from([BRIDGE_POOL_ADDRESS]); // set up the VP - let tx = Tx::new(TxType::Raw); + let tx = Tx::from_type(TxType::Raw); let vp = EthBridge { ctx: setup_ctx( &tx, @@ -691,7 +691,7 @@ mod tests { let verifiers = BTreeSet::from([]); // set up the VP - let tx = Tx::new(TxType::Raw); + let tx = Tx::from_type(TxType::Raw); let vp = EthBridge { ctx: setup_ctx( &tx, diff --git a/shared/src/ledger/native_vp/governance/utils.rs b/shared/src/ledger/native_vp/governance/utils.rs deleted file mode 100644 index c00f57b5d9..0000000000 --- a/shared/src/ledger/native_vp/governance/utils.rs +++ /dev/null @@ -1,484 +0,0 @@ -//! Governance utility functions - -use std::collections::HashMap; - -use borsh::BorshDeserialize; -use namada_core::types::governance::ProposalResult; -use namada_core::types::transaction::governance::ProposalType; -use namada_proof_of_stake::{ - bond_amount, read_all_validator_addresses, read_pos_params, - read_validator_stake, -}; -use thiserror::Error; - -use crate::ledger::governance::storage as gov_storage; -use crate::ledger::pos::BondId; -use crate::ledger::storage_api; -use crate::types::address::Address; -use crate::types::governance::{ - ProposalVote, Tally, TallyResult, VotePower, VoteType, -}; -use crate::types::storage::Epoch; - -/// Proposal structure holding votes information necessary to compute the -/// outcome -pub struct Votes { - /// Map from validators who votes yay to their total stake amount - pub yay_validators: HashMap, - /// Map from delegation votes to their bond amount - pub delegators: - HashMap>, -} - -/// Proposal errors -#[derive(Error, Debug)] -pub enum Error { - /// Invalid validator set deserialization - #[error("Invalid validator set")] - InvalidValidatorSet, - /// Invalid proposal field deserialization - #[error("Invalid proposal {0}")] - InvalidProposal(u64), - /// Error during tally - #[error("Error while tallying proposal: {0}")] - Tally(String), -} - -/// Proposal event definition -pub struct ProposalEvent { - /// Proposal event type - pub event_type: String, - /// Proposal event attributes - pub attributes: HashMap, -} - -impl ProposalEvent { - /// Create a proposal event - pub fn new( - event_type: String, - tally: TallyResult, - id: u64, - has_proposal_code: bool, - proposal_code_exit_status: bool, - ) -> Self { - let attributes = HashMap::from([ - ("tally_result".to_string(), tally.to_string()), - ("proposal_id".to_string(), id.to_string()), - ( - "has_proposal_code".to_string(), - (!has_proposal_code as u64).to_string(), - ), - ( - "proposal_code_exit_status".to_string(), - (!proposal_code_exit_status as u64).to_string(), - ), - ]); - Self { - event_type, - attributes, - } - } -} - -/// Return a proposal result -pub fn compute_tally( - votes: Votes, - total_stake: VotePower, - proposal_type: &ProposalType, -) -> Result { - let Votes { - yay_validators, - delegators, - } = votes; - - match proposal_type { - ProposalType::Default(_) | ProposalType::ETHBridge => { - let mut total_yay_staked_tokens = VotePower::default(); - - for (_, (amount, validator_vote)) in yay_validators.iter() { - if let ProposalVote::Yay(vote_type) = validator_vote { - if proposal_type == vote_type { - total_yay_staked_tokens += *amount; - } else { - // Log the error and continue - tracing::error!( - "Unexpected vote type. Expected: {}, Found: {}", - proposal_type, - validator_vote - ); - continue; - } - } else { - // Log the error and continue - tracing::error!( - "Unexpected vote type. Expected: {}, Found: {}", - proposal_type, - validator_vote - ); - continue; - } - } - - // This loop is taken only for Default proposals - for (_, vote_map) in delegators.iter() { - for (validator_address, (vote_power, delegator_vote)) in - vote_map.iter() - { - match delegator_vote { - ProposalVote::Yay(VoteType::Default) => { - if !yay_validators.contains_key(validator_address) { - // YAY: Add delegator amount whose validator - // didn't vote / voted nay - total_yay_staked_tokens += *vote_power; - } - } - ProposalVote::Nay => { - // NAY: Remove delegator amount whose validator - // validator vote yay - - if yay_validators.contains_key(validator_address) { - total_yay_staked_tokens -= *vote_power; - } - } - - _ => { - // Log the error and continue - tracing::error!( - "Unexpected vote type. Expected: {}, Found: {}", - proposal_type, - delegator_vote - ); - continue; - } - } - } - } - - // Proposal passes if 2/3 of total voting power voted Yay - if total_yay_staked_tokens >= (total_stake / 3) * 2 { - let tally_result = match proposal_type { - ProposalType::Default(_) => { - TallyResult::Passed(Tally::Default) - } - ProposalType::ETHBridge => { - TallyResult::Passed(Tally::ETHBridge) - } - _ => { - return Err(Error::Tally(format!( - "Unexpected proposal type: {}", - proposal_type - ))); - } - }; - - Ok(ProposalResult { - result: tally_result, - total_voting_power: total_stake, - total_yay_power: total_yay_staked_tokens, - total_nay_power: 0.into(), - }) - } else { - Ok(ProposalResult { - result: TallyResult::Rejected, - total_voting_power: total_stake, - total_yay_power: total_yay_staked_tokens, - total_nay_power: 0.into(), - }) - } - } - ProposalType::PGFCouncil => { - let mut total_yay_staked_tokens = HashMap::new(); - for (_, (amount, validator_vote)) in yay_validators.iter() { - if let ProposalVote::Yay(VoteType::PGFCouncil(votes)) = - validator_vote - { - for v in votes { - *total_yay_staked_tokens - .entry(v) - .or_insert(VotePower::zero()) += *amount; - } - } else { - // Log the error and continue - tracing::error!( - "Unexpected vote type. Expected: PGFCouncil, Found: {}", - validator_vote - ); - continue; - } - } - - // YAY: Add delegator amount whose validator didn't vote / voted nay - // or adjust voting power if delegator voted yay with a - // different memo - for (_, vote_map) in delegators.iter() { - for (validator_address, (vote_power, delegator_vote)) in - vote_map.iter() - { - match delegator_vote { - ProposalVote::Yay(VoteType::PGFCouncil( - delegator_votes, - )) => { - match yay_validators.get(validator_address) { - Some((_, validator_vote)) => { - if let ProposalVote::Yay( - VoteType::PGFCouncil(validator_votes), - ) = validator_vote - { - for vote in validator_votes - .symmetric_difference( - delegator_votes, - ) - { - if validator_votes.contains(vote) { - // Delegator didn't vote for - // this, reduce voting power - if let Some(power) = - total_yay_staked_tokens - .get_mut(vote) - { - *power -= *vote_power; - } else { - return Err(Error::Tally( - format!( - "Expected PGF \ - vote {:?} was \ - not in tally", - vote - ), - )); - } - } else { - // Validator didn't vote for - // this, add voting power - *total_yay_staked_tokens - .entry(vote) - .or_insert( - VotePower::zero(), - ) += *vote_power; - } - } - } else { - // Log the error and continue - tracing::error!( - "Unexpected vote type. Expected: \ - PGFCouncil, Found: {}", - validator_vote - ); - continue; - } - } - None => { - // Validator didn't vote or voted nay, add - // delegator vote - - for vote in delegator_votes { - *total_yay_staked_tokens - .entry(vote) - .or_insert(VotePower::zero()) += - *vote_power; - } - } - } - } - ProposalVote::Nay => { - for ( - validator_address, - (vote_power, _delegator_vote), - ) in vote_map.iter() - { - if let Some((_, validator_vote)) = - yay_validators.get(validator_address) - { - if let ProposalVote::Yay( - VoteType::PGFCouncil(votes), - ) = validator_vote - { - for vote in votes { - if let Some(power) = - total_yay_staked_tokens - .get_mut(vote) - { - *power -= *vote_power; - } else { - return Err(Error::Tally( - format!( - "Expected PGF vote \ - {:?} was not in tally", - vote - ), - )); - } - } - } else { - // Log the error and continue - tracing::error!( - "Unexpected vote type. Expected: \ - PGFCouncil, Found: {}", - validator_vote - ); - continue; - } - } - } - } - _ => { - // Log the error and continue - tracing::error!( - "Unexpected vote type. Expected: PGFCouncil, \ - Found: {}", - delegator_vote - ); - continue; - } - } - } - } - - // At least 1/3 of the total voting power must vote Yay - let total_yay_voted_power = total_yay_staked_tokens - .iter() - .fold(VotePower::zero(), |acc, (_, vote_power)| { - acc + *vote_power - }); - - match total_yay_voted_power.checked_mul(3.into()) { - Some(v) if v < total_stake => Ok(ProposalResult { - result: TallyResult::Rejected, - total_voting_power: total_stake, - total_yay_power: total_yay_voted_power, - total_nay_power: VotePower::zero(), - }), - _ => { - // Select the winner council based on approval voting - // (majority) - let council = total_yay_staked_tokens - .into_iter() - .max_by(|a, b| a.1.cmp(&b.1)) - .map(|(vote, _)| vote.to_owned()) - .ok_or_else(|| { - Error::Tally( - "Missing expected elected council".to_string(), - ) - })?; - - Ok(ProposalResult { - result: TallyResult::Passed(Tally::PGFCouncil(council)), - total_voting_power: total_stake, - total_yay_power: total_yay_voted_power, - total_nay_power: VotePower::zero(), - }) - } - } - } - } -} - -/// Prepare Votes structure to compute proposal tally -pub fn get_proposal_votes( - storage: &S, - epoch: Epoch, - proposal_id: u64, -) -> storage_api::Result -where - S: storage_api::StorageRead, -{ - let params = read_pos_params(storage)?; - let validators = read_all_validator_addresses(storage, epoch)?; - - let vote_prefix_key = - gov_storage::get_proposal_vote_prefix_key(proposal_id); - let vote_iter = - storage_api::iter_prefix::(storage, &vote_prefix_key)?; - - let mut yay_validators = HashMap::new(); - let mut delegators: HashMap< - Address, - HashMap, - > = HashMap::new(); - - for next_vote in vote_iter { - let (vote_key, vote) = next_vote?; - let voter_address = gov_storage::get_voter_address(&vote_key); - match voter_address { - Some(voter_address) => { - if vote.is_yay() && validators.contains(voter_address) { - let amount: VotePower = read_validator_stake( - storage, - ¶ms, - voter_address, - epoch, - )? - .unwrap_or_default() - .try_into() - .expect("Amount out of bounds"); - - yay_validators - .insert(voter_address.clone(), (amount, vote)); - } else if !validators.contains(voter_address) { - let validator_address = - gov_storage::get_vote_delegation_address(&vote_key); - match validator_address { - Some(validator) => { - let bond_id = BondId { - source: voter_address.clone(), - validator: validator.clone(), - }; - let amount = - bond_amount(storage, &bond_id, epoch)?.1; - - if !amount.is_zero() { - let entry = delegators - .entry(voter_address.to_owned()) - .or_default(); - entry.insert( - validator.to_owned(), - ( - VotePower::try_from(amount).unwrap(), - vote, - ), - ); - } - } - None => continue, - } - } - } - None => continue, - } - } - - Ok(Votes { - yay_validators, - delegators, - }) -} - -/// Calculate the valid voting window for validator given a proposal epoch -/// details -pub fn is_valid_validator_voting_period( - current_epoch: Epoch, - voting_start_epoch: Epoch, - voting_end_epoch: Epoch, -) -> bool { - voting_start_epoch < voting_end_epoch - && current_epoch * 3 <= voting_start_epoch + voting_end_epoch * 2 -} - -/// Check if an accepted proposal is being executed -pub fn is_proposal_accepted( - storage: &S, - tx_data: &[u8], -) -> storage_api::Result -where - S: storage_api::StorageRead, -{ - let proposal_id = u64::try_from_slice(tx_data).ok(); - match proposal_id { - Some(id) => { - let proposal_execution_key = - gov_storage::get_proposal_execution_key(id); - storage.has_key(&proposal_execution_key) - } - None => Ok(false), - } -} diff --git a/shared/src/ledger/native_vp/mod.rs b/shared/src/ledger/native_vp/mod.rs index ed34545f16..02a3435397 100644 --- a/shared/src/ledger/native_vp/mod.rs +++ b/shared/src/ledger/native_vp/mod.rs @@ -2,11 +2,9 @@ //! as the PoS and IBC modules. pub mod ethereum_bridge; -pub mod governance; pub mod multitoken; pub mod parameters; pub mod replay_protection; -pub mod slash_fund; use std::cell::RefCell; use std::collections::BTreeSet; diff --git a/shared/src/ledger/native_vp/multitoken.rs b/shared/src/ledger/native_vp/multitoken.rs index 5b88c0f152..3a15da97aa 100644 --- a/shared/src/ledger/native_vp/multitoken.rs +++ b/shared/src/ledger/native_vp/multitoken.rs @@ -164,7 +164,7 @@ mod tests { fn dummy_tx(wl_storage: &TestWlStorage) -> Tx { let tx_code = vec![]; let tx_data = vec![]; - let mut tx = Tx::new(TxType::Raw); + let mut tx = Tx::from_type(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)); diff --git a/shared/src/ledger/native_vp/parameters.rs b/shared/src/ledger/native_vp/parameters.rs index bb1db0ab30..a2559ad0ab 100644 --- a/shared/src/ledger/native_vp/parameters.rs +++ b/shared/src/ledger/native_vp/parameters.rs @@ -8,7 +8,7 @@ use namada_core::types::address::Address; use namada_core::types::storage::Key; use thiserror::Error; -use super::governance; +use crate::core::ledger::storage_api::governance; use crate::ledger::native_vp::{self, Ctx, NativeVp}; use crate::vm::WasmCacheAccess; @@ -55,11 +55,10 @@ where return false; }; match key_type { - KeyType::PARAMETER => governance::utils::is_proposal_accepted( - &self.ctx.pre(), - &data, - ) - .unwrap_or(false), + KeyType::PARAMETER => { + governance::is_proposal_accepted(&self.ctx.pre(), &data) + .unwrap_or(false) + } KeyType::UNKNOWN_PARAMETER => false, KeyType::UNKNOWN => true, } diff --git a/shared/src/ledger/pgf/mod.rs b/shared/src/ledger/pgf/mod.rs new file mode 100644 index 0000000000..f402b0f97b --- /dev/null +++ b/shared/src/ledger/pgf/mod.rs @@ -0,0 +1,126 @@ +//! Pgf VP + +/// Pgf utility functions and structures +pub mod utils; + +use std::collections::BTreeSet; + +use namada_core::ledger::pgf::storage::keys as pgf_storage; +use namada_core::ledger::storage; +use namada_core::ledger::storage_api::governance::is_proposal_accepted; +use namada_core::proto::Tx; +use thiserror::Error; + +use crate::ledger::native_vp; +use crate::ledger::native_vp::{Ctx, NativeVp}; +use crate::types::address::{Address, InternalAddress}; +use crate::types::storage::Key; +use crate::vm::WasmCacheAccess; + +/// for handling Pgf NativeVP errors +pub type Result = std::result::Result; + +/// The PGF internal address +pub const ADDRESS: Address = Address::Internal(InternalAddress::Pgf); + +#[allow(missing_docs)] +#[derive(Error, Debug)] +pub enum Error { + #[error("Native VP error: {0}")] + NativeVpError(#[from] native_vp::Error), +} + +/// Pgf VP +pub struct PgfVp<'a, DB, H, CA> +where + DB: storage::DB + for<'iter> storage::DBIter<'iter>, + H: storage::StorageHasher, + CA: WasmCacheAccess, +{ + /// Context to interact with the host structures. + pub ctx: Ctx<'a, DB, H, CA>, +} + +impl<'a, DB, H, CA> NativeVp for PgfVp<'a, DB, H, CA> +where + DB: 'static + storage::DB + for<'iter> storage::DBIter<'iter>, + H: 'static + storage::StorageHasher, + CA: 'static + WasmCacheAccess, +{ + type Error = Error; + + fn validate_tx( + &self, + tx_data: &Tx, + keys_changed: &BTreeSet, + _verifiers: &BTreeSet
, + ) -> Result { + let result = keys_changed.iter().all(|key| { + let key_type = KeyType::from(key); + + let result = match key_type { + KeyType::STEWARDS => Ok(false), + KeyType::PAYMENTS => Ok(false), + KeyType::PGF_INFLATION_RATE + | KeyType::STEWARD_INFLATION_RATE => { + self.is_valid_parameter_change(tx_data) + } + KeyType::UNKNOWN_PGF => Ok(false), + KeyType::UNKNOWN => Ok(true), + }; + result.unwrap_or(false) + }); + Ok(result) + } +} + +impl<'a, DB, H, CA> PgfVp<'a, DB, H, CA> +where + DB: 'static + storage::DB + for<'iter> storage::DBIter<'iter>, + H: 'static + storage::StorageHasher, + CA: 'static + WasmCacheAccess, +{ + /// Validate a governance parameter + pub fn is_valid_parameter_change(&self, tx: &Tx) -> Result { + match tx.data() { + Some(data) => is_proposal_accepted(&self.ctx.pre(), data.as_ref()) + .map_err(Error::NativeVpError), + None => Ok(true), + } + } +} + +#[allow(clippy::upper_case_acronyms)] +#[derive(Debug)] +enum KeyType { + #[allow(non_camel_case_types)] + STEWARDS, + #[allow(non_camel_case_types)] + PAYMENTS, + #[allow(non_camel_case_types)] + PGF_INFLATION_RATE, + #[allow(non_camel_case_types)] + STEWARD_INFLATION_RATE, + #[allow(non_camel_case_types)] + UNKNOWN_PGF, + #[allow(non_camel_case_types)] + UNKNOWN, +} + +impl From<&Key> for KeyType { + fn from(key: &Key) -> Self { + if pgf_storage::is_stewards_key(key) { + Self::STEWARDS + } else if pgf_storage::is_payments_key(key) { + KeyType::PAYMENTS + } else if pgf_storage::is_pgf_inflation_rate_key(key) { + Self::PGF_INFLATION_RATE + } else if pgf_storage::is_steward_inflation_rate_key(key) { + Self::STEWARD_INFLATION_RATE + } else if pgf_storage::is_pgf_key(key) { + KeyType::UNKNOWN_PGF + } else { + KeyType::UNKNOWN + } + } +} diff --git a/shared/src/ledger/pgf/utils.rs b/shared/src/ledger/pgf/utils.rs new file mode 100644 index 0000000000..e1bec701ba --- /dev/null +++ b/shared/src/ledger/pgf/utils.rs @@ -0,0 +1,66 @@ +use std::collections::HashMap; + +use namada_core::types::address::Address; +use namada_core::types::token; + +use crate::ledger::events::EventType; + +/// Proposal event definition +pub struct ProposalEvent { + /// Proposal event type + pub event_type: String, + /// Proposal event attributes + pub attributes: HashMap, +} + +impl ProposalEvent { + /// Create a proposal event + pub fn new( + event_type: String, + target: Address, + amount: token::Amount, + is_steward: bool, + success: bool, + ) -> Self { + let attributes = HashMap::from([ + ("target".to_string(), target.to_string()), + ("amount".to_string(), amount.to_string_native()), + ("is_steward".to_string(), is_steward.to_string()), + ("successed".to_string(), success.to_string()), + ]); + Self { + event_type, + attributes, + } + } + + /// Create a new proposal event for pgf continous funding + pub fn pgf_funding_payment( + target: Address, + amount: token::Amount, + success: bool, + ) -> Self { + ProposalEvent::new( + EventType::PgfPayment.to_string(), + target, + amount, + false, + success, + ) + } + + /// Create a new proposal event for steward payments + pub fn pgf_steward_payment( + target: Address, + amount: token::Amount, + success: bool, + ) -> Self { + ProposalEvent::new( + EventType::PgfPayment.to_string(), + target, + amount, + true, + success, + ) + } +} diff --git a/shared/src/ledger/pos/vp.rs b/shared/src/ledger/pos/vp.rs index 18085c5c53..76607c3199 100644 --- a/shared/src/ledger/pos/vp.rs +++ b/shared/src/ledger/pos/vp.rs @@ -3,6 +3,7 @@ use std::collections::BTreeSet; use std::panic::{RefUnwindSafe, UnwindSafe}; +use namada_core::ledger::storage_api::governance; // use borsh::BorshDeserialize; pub use namada_proof_of_stake; pub use namada_proof_of_stake::parameters::PosParams; @@ -12,7 +13,7 @@ pub use namada_proof_of_stake::types; use thiserror::Error; use super::is_params_key; -use crate::ledger::native_vp::{self, governance, Ctx, NativeVp}; +use crate::ledger::native_vp::{self, Ctx, NativeVp}; // use crate::ledger::pos::{ // is_validator_address_raw_hash_key, // is_validator_max_commission_rate_change_key, @@ -106,18 +107,14 @@ where tracing::debug!("\nValidating PoS Tx\n"); for key in keys_changed { - // println!("KEY: {}\n", key); if is_params_key(key) { let data = if let Some(data) = tx_data.data() { data } else { return Ok(false); }; - if !governance::utils::is_proposal_accepted( - &self.ctx.pre(), - &data, - ) - .map_err(Error::NativeVpError)? + if !governance::is_proposal_accepted(&self.ctx.pre(), &data) + .map_err(Error::NativeVpError)? { return Ok(false); } diff --git a/shared/src/ledger/protocol/mod.rs b/shared/src/ledger/protocol/mod.rs index 6cab156d7a..7a0244932a 100644 --- a/shared/src/ledger/protocol/mod.rs +++ b/shared/src/ledger/protocol/mod.rs @@ -8,15 +8,15 @@ use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use thiserror::Error; use crate::ledger::gas::{self, BlockGasMeter, VpGasMeter}; +use crate::ledger::governance::GovernanceVp; use crate::ledger::ibc::vp::Ibc; use crate::ledger::native_vp::ethereum_bridge::bridge_pool_vp::BridgePoolVp; use crate::ledger::native_vp::ethereum_bridge::vp::EthBridge; -use crate::ledger::native_vp::governance::GovernanceVp; use crate::ledger::native_vp::multitoken::MultitokenVp; use crate::ledger::native_vp::parameters::{self, ParametersVp}; use crate::ledger::native_vp::replay_protection::ReplayProtectionVp; -use crate::ledger::native_vp::slash_fund::SlashFundVp; use crate::ledger::native_vp::{self, NativeVp}; +use crate::ledger::pgf::PgfVp; use crate::ledger::pos::{self, PosVP}; use crate::ledger::storage::write_log::WriteLog; use crate::ledger::storage::{DBIter, Storage, StorageHasher, WlStorage, DB}; @@ -61,9 +61,9 @@ pub enum Error { #[error("IBC Token native VP: {0}")] MultitokenNativeVpError(crate::ledger::native_vp::multitoken::Error), #[error("Governance native VP error: {0}")] - GovernanceNativeVpError(crate::ledger::native_vp::governance::Error), - #[error("SlashFund native VP error: {0}")] - SlashFundNativeVpError(crate::ledger::native_vp::slash_fund::Error), + GovernanceNativeVpError(crate::ledger::governance::Error), + #[error("Pgf native VP error: {0}")] + PgfNativeVpError(crate::ledger::pgf::Error), #[error("Ethereum bridge native VP error: {0}")] EthBridgeNativeVpError(native_vp::ethereum_bridge::vp::Error), #[error("Ethereum bridge pool native VP error: {0}")] @@ -543,14 +543,6 @@ where gas_meter = governance.ctx.gas_meter.into_inner(); result } - InternalAddress::SlashFund => { - let slash_fund = SlashFundVp { ctx }; - let result = slash_fund - .validate_tx(tx, &keys_changed, &verifiers) - .map_err(Error::SlashFundNativeVpError); - gas_meter = slash_fund.ctx.gas_meter.into_inner(); - result - } InternalAddress::Multitoken => { let multitoken = MultitokenVp { ctx }; let result = multitoken @@ -585,6 +577,14 @@ where replay_protection_vp.ctx.gas_meter.into_inner(); result } + InternalAddress::Pgf => { + let pgf_vp = PgfVp { ctx }; + let result = pgf_vp + .validate_tx(tx, &keys_changed, &verifiers) + .map_err(Error::PgfNativeVpError); + gas_meter = pgf_vp.ctx.gas_meter.into_inner(); + result + } InternalAddress::IbcToken(_) | InternalAddress::Erc20(_) => { // The address should be a part of a multitoken key diff --git a/shared/src/ledger/queries/shell.rs b/shared/src/ledger/queries/shell.rs index 3eb95c8e8c..94412f1a15 100644 --- a/shared/src/ledger/queries/shell.rs +++ b/shared/src/ledger/queries/shell.rs @@ -5,6 +5,7 @@ use masp_primitives::asset_type::AssetType; use masp_primitives::merkle_tree::MerklePath; use masp_primitives::sapling::Node; use namada_core::ledger::storage::LastBlock; +use namada_core::types::account::{Account, AccountPublicKeysMap}; use namada_core::types::address::Address; use namada_core::types::hash::Hash; use namada_core::types::storage::{BlockHeight, BlockResults, KeySeg}; @@ -75,6 +76,12 @@ router! {SHELL, // was the transaction applied? ( "applied" / [tx_hash: Hash] ) -> Option = applied, + // Query account subspace + ( "account" / [owner: Address] ) -> Option = account, + + // Query public key revealad + ( "revealed" / [owner: Address] ) -> bool = revealed, + // IBC UpdateClient event ( "ibc_client_update" / [client_id: ClientId] / [consensus_height: BlockHeight] ) -> Option = ibc_client_update, @@ -438,6 +445,46 @@ where .cloned()) } +fn account( + ctx: RequestCtx<'_, D, H>, + owner: Address, +) -> storage_api::Result> +where + D: 'static + DB + for<'iter> DBIter<'iter> + Sync, + H: 'static + StorageHasher + Sync, +{ + let account_exists = storage_api::account::exists(ctx.wl_storage, &owner)?; + + if account_exists { + let public_keys = + storage_api::account::public_keys(ctx.wl_storage, &owner)?; + let threshold = + storage_api::account::threshold(ctx.wl_storage, &owner)?; + + Ok(Some(Account { + public_keys_map: AccountPublicKeysMap::from_iter(public_keys), + address: owner, + threshold: threshold.unwrap_or(1), + })) + } else { + Ok(None) + } +} + +fn revealed( + ctx: RequestCtx<'_, D, H>, + owner: Address, +) -> storage_api::Result +where + D: 'static + DB + for<'iter> DBIter<'iter> + Sync, + H: 'static + StorageHasher + Sync, +{ + let public_keys = + storage_api::account::public_keys(ctx.wl_storage, &owner)?; + + Ok(!public_keys.is_empty()) +} + #[cfg(test)] mod test { @@ -492,7 +539,8 @@ mod test { assert_eq!(current_epoch, read_epoch); // Request dry run tx - let mut outer_tx = Tx::new(TxType::Decrypted(DecryptedTx::Decrypted { + let mut outer_tx = + Tx::from_type(TxType::Decrypted(DecryptedTx::Decrypted { #[cfg(not(feature = "mainnet"))] // To be able to dry-run testnet faucet withdrawal, pretend // that we got a valid PoW diff --git a/shared/src/ledger/queries/vp/governance.rs b/shared/src/ledger/queries/vp/governance.rs new file mode 100644 index 0000000000..230612cbb8 --- /dev/null +++ b/shared/src/ledger/queries/vp/governance.rs @@ -0,0 +1,38 @@ +// cd shared && cargo expand ledger::queries::vp::governance + +use namada_core::ledger::governance::storage::proposal::StorageProposal; +use namada_core::ledger::governance::utils::Vote; + +use crate::ledger::queries::types::RequestCtx; +use crate::ledger::storage::{DBIter, StorageHasher, DB}; +use crate::ledger::storage_api; + +// Governance queries +router! {GOV, + ( "proposal" / [id: u64 ] ) -> Option = proposal_id, + ( "proposal" / [id: u64 ] / "votes" ) -> Vec = proposal_id_votes, +} + +/// Find if the given address belongs to a validator account. +fn proposal_id( + ctx: RequestCtx<'_, D, H>, + id: u64, +) -> storage_api::Result> +where + D: 'static + DB + for<'iter> DBIter<'iter> + Sync, + H: 'static + StorageHasher + Sync, +{ + storage_api::governance::get_proposal_by_id(ctx.wl_storage, id) +} + +/// Find if the given address belongs to a validator account. +fn proposal_id_votes( + ctx: RequestCtx<'_, D, H>, + id: u64, +) -> storage_api::Result> +where + D: 'static + DB + for<'iter> DBIter<'iter> + Sync, + H: 'static + StorageHasher + Sync, +{ + storage_api::governance::get_proposal_votes(ctx.wl_storage, id) +} diff --git a/shared/src/ledger/queries/vp/mod.rs b/shared/src/ledger/queries/vp/mod.rs index ad05a2b88b..c53386b2f8 100644 --- a/shared/src/ledger/queries/vp/mod.rs +++ b/shared/src/ledger/queries/vp/mod.rs @@ -1,10 +1,16 @@ //! Queries router and handlers for validity predicates // Re-export to show in rustdoc! +pub use governance::Gov; +use governance::GOV; pub use pos::Pos; use pos::POS; pub use token::Token; use token::TOKEN; +mod governance; +pub use pgf::Pgf; +use pgf::PGF; +mod pgf; pub mod pos; mod token; @@ -13,6 +19,8 @@ mod token; router! {VP, ( "pos" ) = (sub POS), ( "token" ) = (sub TOKEN), + ( "governance" ) = (sub GOV), + ( "pgf" ) = (sub PGF), } /// Client-only methods for the router type are composed from router functions. diff --git a/shared/src/ledger/queries/vp/pgf.rs b/shared/src/ledger/queries/vp/pgf.rs new file mode 100644 index 0000000000..932d898068 --- /dev/null +++ b/shared/src/ledger/queries/vp/pgf.rs @@ -0,0 +1,36 @@ +use std::collections::BTreeSet; + +use namada_core::ledger::governance::storage::proposal::PGFTarget; +use namada_core::types::address::Address; + +use crate::ledger::queries::types::RequestCtx; +use crate::ledger::storage::{DBIter, StorageHasher, DB}; +use crate::ledger::storage_api; + +// PoS validity predicate queries +router! {PGF, + ( "stewards" ) -> BTreeSet
= stewards, + ( "fundings" ) -> BTreeSet = funding, +} + +/// Query the currect pgf steward set +fn stewards( + ctx: RequestCtx<'_, D, H>, +) -> storage_api::Result> +where + D: 'static + DB + for<'iter> DBIter<'iter> + Sync, + H: 'static + StorageHasher + Sync, +{ + storage_api::pgf::get_stewards(ctx.wl_storage) +} + +/// Query the continous pgf fundings +fn funding( + ctx: RequestCtx<'_, D, H>, +) -> storage_api::Result> +where + D: 'static + DB + for<'iter> DBIter<'iter> + Sync, + H: 'static + StorageHasher + Sync, +{ + storage_api::pgf::get_payments(ctx.wl_storage) +} diff --git a/shared/src/ledger/queries/vp/pos.rs b/shared/src/ledger/queries/vp/pos.rs index 075b936e25..aff5181a19 100644 --- a/shared/src/ledger/queries/vp/pos.rs +++ b/shared/src/ledger/queries/vp/pos.rs @@ -69,6 +69,9 @@ router! {POS, ( "delegations" / [owner: Address] ) -> HashSet
= delegation_validators, + ( "delegations_at" / [owner: Address] / [epoch: opt Epoch] ) + -> HashMap = delegations, + ( "bond_deltas" / [source: Address] / [validator: Address] ) -> HashMap = bond_deltas, @@ -463,7 +466,6 @@ where /// Find all the validator addresses to whom the given `owner` address has /// some delegation in any epoch -#[allow(dead_code)] fn delegations( ctx: RequestCtx<'_, D, H>, owner: Address, diff --git a/shared/src/ledger/rpc.rs b/shared/src/ledger/rpc.rs index 1bd42018c5..73189d7aa7 100644 --- a/shared/src/ledger/rpc.rs +++ b/shared/src/ledger/rpc.rs @@ -8,8 +8,13 @@ use borsh::BorshDeserialize; use masp_primitives::asset_type::AssetType; use masp_primitives::merkle_tree::MerklePath; use masp_primitives::sapling::Node; +use namada_core::ledger::governance::parameters::GovernanceParameters; +use namada_core::ledger::governance::storage::proposal::StorageProposal; +use namada_core::ledger::governance::utils::Vote; use namada_core::ledger::storage::LastBlock; +#[cfg(not(feature = "mainnet"))] use namada_core::ledger::testnet_pow; +use namada_core::types::account::Account; use namada_core::types::address::Address; use namada_core::types::storage::Key; use namada_core::types::token::{ @@ -21,11 +26,9 @@ use namada_proof_of_stake::types::{ }; use serde::Serialize; +use crate::core::ledger::governance::storage::keys as gov_storage; use crate::ledger::args::InputAmount; use crate::ledger::events::Event; -use crate::ledger::governance::parameters::GovParams; -use crate::ledger::governance::storage as gov_storage; -use crate::ledger::native_vp::governance::utils::Votes; use crate::ledger::queries::vp::pos::EnrichedBondsAndUnbondsDetails; use crate::ledger::queries::RPC; use crate::proto::Tx; @@ -35,10 +38,9 @@ use crate::tendermint_rpc::error::Error as TError; use crate::tendermint_rpc::query::Query; use crate::tendermint_rpc::Order; use crate::types::control_flow::{time, Halt, TryHalt}; -use crate::types::governance::{ProposalVote, VotePower}; use crate::types::hash::Hash; use crate::types::io::Io; -use crate::types::key::*; +use crate::types::key::common; use crate::types::storage::{BlockHeight, BlockResults, Epoch, PrefixValue}; use crate::types::{storage, token}; use crate::{display_line, edisplay_line}; @@ -127,8 +129,8 @@ pub async fn query_block( fn unwrap_client_response( response: Result, ) -> T { - response.unwrap_or_else(|_err| { - panic!("Error in the query"); + response.unwrap_or_else(|err| { + panic!("Error in the query: {:?}", err.to_string()); }) } @@ -150,15 +152,6 @@ pub async fn get_token_balance( ) } -/// Get account's public key stored in its storage sub-space -pub async fn get_public_key( - client: &C, - address: &Address, -) -> Option { - let key = pk_key(address); - query_storage_value(client, &key).await -} - /// Check if the given address is a known validator. pub async fn is_validator( client: &C, @@ -650,73 +643,6 @@ pub async fn query_tx_response( Ok(result) } -/// Get the votes for a given proposal id -pub async fn get_proposal_votes< - C: crate::ledger::queries::Client + Sync, - IO: Io, ->( - client: &C, - epoch: Epoch, - proposal_id: u64, -) -> Votes { - let validators = get_all_validators(client, epoch).await; - - let vote_prefix_key = - gov_storage::get_proposal_vote_prefix_key(proposal_id); - let vote_iter = - query_storage_prefix::(client, &vote_prefix_key) - .await; - - let mut yay_validators: HashMap = - HashMap::new(); - let mut delegators: HashMap< - Address, - HashMap, - > = HashMap::new(); - - if let Some(vote_iter) = vote_iter { - for (key, vote) in vote_iter { - let voter_address = gov_storage::get_voter_address(&key) - .expect("Vote key should contain the voting address.") - .clone(); - if vote.is_yay() && validators.contains(&voter_address) { - let amount: VotePower = - get_validator_stake(client, epoch, &voter_address) - .await - .try_into() - .expect("Amount of bonds"); - yay_validators.insert(voter_address, (amount, vote)); - } else if !validators.contains(&voter_address) { - let validator_address = - gov_storage::get_vote_delegation_address(&key) - .expect( - "Vote key should contain the delegation address.", - ) - .clone(); - let delegator_token_amount = get_bond_amount_at( - client, - &voter_address, - &validator_address, - epoch, - ) - .await; - if let Some(amount) = delegator_token_amount { - let entry = delegators.entry(voter_address).or_default(); - entry.insert( - validator_address, - (VotePower::from(amount), vote), - ); - } - } - } - } - - Votes { - yay_validators, - delegators, - } -} - /// Get the PoS parameters pub async fn get_pos_params( client: &C, @@ -790,6 +716,32 @@ pub async fn get_delegators_delegation< ) } +/// Get the delegator's delegation at some epoh +pub async fn get_delegators_delegation_at< + C: crate::ledger::queries::Client + Sync, +>( + client: &C, + address: &Address, + epoch: Epoch, +) -> HashMap { + unwrap_client_response::( + RPC.vp() + .pos() + .delegations(client, address, &Some(epoch)) + .await, + ) +} + +/// Query proposal by Id +pub async fn query_proposal_by_id( + client: &C, + proposal_id: u64, +) -> Option { + unwrap_client_response::( + RPC.vp().gov().proposal_id(client, &proposal_id).await, + ) +} + /// Query and return validator's commission rate and max commission rate change /// per epoch pub async fn query_commission_rate( @@ -817,6 +769,42 @@ pub async fn query_bond( ) } +/// Query the accunt substorage space of an address +pub async fn get_account_info( + client: &C, + owner: &Address, +) -> Option { + unwrap_client_response::>( + RPC.shell().account(client, owner).await, + ) +} + +/// Query if the public_key is revealed +pub async fn is_public_key_revealed< + C: crate::ledger::queries::Client + Sync, +>( + client: &C, + owner: &Address, +) -> bool { + unwrap_client_response::(RPC.shell().revealed(client, owner).await) +} + +/// Query an account substorage at a specific index +pub async fn get_public_key_at( + client: &C, + owner: &Address, + index: u8, +) -> Option { + let account = unwrap_client_response::>( + RPC.shell().account(client, owner).await, + ); + if let Some(account) = account { + account.get_public_key_from_index(index) + } else { + None + } +} + /// Query a validator's unbonds for a given epoch pub async fn query_and_print_unbonds< C: crate::ledger::queries::Client + Sync, @@ -893,11 +881,11 @@ pub async fn query_unbond_with_slashing< } /// Get the givernance parameters -pub async fn get_governance_parameters< +pub async fn query_governance_parameters< C: crate::ledger::queries::Client + Sync, >( client: &C, -) -> GovParams { +) -> GovernanceParameters { let key = gov_storage::get_max_proposal_code_size_key(); let max_proposal_code_size = query_storage_value::(client, &key) .await @@ -918,27 +906,37 @@ pub async fn get_governance_parameters< .await .expect("Parameter should be definied."); - let key = gov_storage::get_min_proposal_period_key(); - let min_proposal_period = query_storage_value::(client, &key) - .await - .expect("Parameter should be definied."); + let key = gov_storage::get_min_proposal_voting_period_key(); + let min_proposal_voting_period = + query_storage_value::(client, &key) + .await + .expect("Parameter should be definied."); let key = gov_storage::get_max_proposal_period_key(); let max_proposal_period = query_storage_value::(client, &key) .await .expect("Parameter should be definied."); - GovParams { - min_proposal_fund: u128::try_from(min_proposal_fund) - .expect("Amount out of bounds") as u64, + GovernanceParameters { + min_proposal_fund, max_proposal_code_size, - min_proposal_period, + min_proposal_voting_period, max_proposal_period, max_proposal_content_size, min_proposal_grace_epochs, } } +/// Get the givernance parameters +pub async fn query_proposal_votes( + client: &C, + proposal_id: u64, +) -> Vec { + unwrap_client_response::>( + RPC.vp().gov().proposal_id_votes(client, &proposal_id).await, + ) +} + /// Get the bond amount at the given epoch pub async fn get_bond_amount_at( client: &C, diff --git a/shared/src/ledger/signing.rs b/shared/src/ledger/signing.rs index 31e2256c3a..b25084055d 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; @@ -15,46 +9,45 @@ use masp_primitives::asset_type::AssetType; use masp_primitives::transaction::components::sapling::fees::{ InputView, OutputView, }; +use namada_core::proto::SignatureIndex; +use namada_core::types::account::AccountPublicKeysMap; use namada_core::types::address::{ masp, masp_tx_key, Address, ImplicitAddress, }; +// use namada_core::types::storage::Key; use namada_core::types::token::{self, Amount, DenominatedAmount, MaspDenom}; -use namada_core::types::transaction::{pos, MIN_FEE}; +use namada_core::types::transaction::pos; use prost::Message; use serde::{Deserialize, Serialize}; use zeroize::Zeroizing; -use crate::ibc::applications::transfer::msgs::transfer::{ - MsgTransfer, TYPE_URL as MSG_TRANSFER_TYPE_URL, -}; +use crate::display_line; +use crate::ibc::applications::transfer::msgs::transfer::MsgTransfer; use crate::ibc_proto::google::protobuf::Any; use crate::ledger::masp::make_asset_type; use crate::ledger::parameters::storage as parameter_storage; -use crate::ledger::rpc::{ - format_denominated_amount, query_wasm_code_hash, TxBroadcastData, -}; +use crate::ledger::rpc::{format_denominated_amount, query_wasm_code_hash}; use crate::ledger::tx::{ Error, TX_BOND_WASM, TX_CHANGE_COMMISSION_WASM, TX_IBC_WASM, TX_INIT_ACCOUNT_WASM, TX_INIT_PROPOSAL, TX_INIT_VALIDATOR_WASM, - TX_REVEAL_PK, TX_TRANSFER_WASM, TX_UNBOND_WASM, TX_UPDATE_VP_WASM, + TX_REVEAL_PK, TX_TRANSFER_WASM, TX_UNBOND_WASM, TX_UPDATE_ACCOUNT_WASM, TX_VOTE_PROPOSAL, TX_WITHDRAW_WASM, VP_USER_WASM, }; pub use crate::ledger::wallet::store::AddressVpType; use crate::ledger::wallet::{Wallet, WalletUtils}; use crate::ledger::{args, rpc}; -use crate::proto::{MaspBuilder, Section, Signature, Tx}; -use crate::types::io::Io; +use crate::proto::{MaspBuilder, Section, Tx}; +use crate::types::io::*; use crate::types::key::*; use crate::types::masp::{ExtendedViewingKey, PaymentAddress}; use crate::types::storage::Epoch; use crate::types::token::Transfer; +use crate::types::transaction::account::{InitAccount, UpdateAccount}; use crate::types::transaction::governance::{ InitProposalData, VoteProposalData, }; -use crate::types::transaction::{ - Fee, InitAccount, InitValidator, TxType, UpdateVp, WrapperTx, -}; -use crate::{display_line, edisplay_line}; +use crate::types::transaction::pos::InitValidator; +use crate::types::transaction::{Fee, TxType}; #[cfg(feature = "std")] /// Env. var specifying where to store signing test vectors @@ -63,6 +56,19 @@ 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: Option, + /// The public keys of the fee payer + pub gas_payer: common::PublicKey, +} + /// 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 @@ -84,12 +90,12 @@ pub async fn find_pk< "Looking-up public key of {} from the ledger...", addr.encode() ); - rpc::get_public_key(client, addr).await.ok_or(Error::Other( - format!( + rpc::get_public_key_at(client, addr, 0) + .await + .ok_or(Error::Other(format!( "No public key found for the address {}", addr.encode() - ), - )) + ))) } Address::Implicit(ImplicitAddress(pkh)) => Ok(wallet .find_key_by_pkh(pkh, password) @@ -115,48 +121,30 @@ pub async fn find_pk< pub fn find_key_by_pk( wallet: &mut Wallet, args: &args::Tx, - keypair: &common::PublicKey, + public_key: &common::PublicKey, ) -> Result { - if *keypair == masp_tx_key().ref_to() { + if *public_key == masp_tx_key().ref_to() { // We already know the secret key corresponding to the MASP sentinal key Ok(masp_tx_key()) - } else if args - .signing_key - .as_ref() - .map(|x| x.ref_to() == *keypair) - .unwrap_or(false) - { - // We can lookup the secret key from the CLI arguments in this case - Ok(args.signing_key.clone().unwrap()) } else { // Otherwise we need to search the wallet for the secret key wallet - .find_key_by_pk(keypair, args.password.clone()) + .find_key_by_pk(public_key, args.password.clone()) .map_err(|err| { Error::Other(format!( "Unable to load the keypair from the wallet for public \ key {}. Failed with: {}", - keypair, err + public_key, err )) }) } } -/// Carries types that can be directly/indirectly used to sign a transaction. -#[allow(clippy::large_enum_variant)] -#[derive(Clone)] -pub enum TxSigningKey { - /// Do not sign any transaction - None, - /// Obtain the keypair corresponding to given address from wallet and sign - WalletAddress(Address), -} - /// Given CLI arguments and some defaults, determine the rightful transaction /// 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, IO: Io, @@ -164,34 +152,27 @@ pub async fn tx_signer< client: &C, wallet: &mut Wallet, args: &args::Tx, - default: TxSigningKey, -) -> Result<(Option
, common::PublicKey), Error> { - let signer = if args.dry_run { - // We cannot override the signer if we're doing a dry run - default - } else if let Some(signing_key) = &args.signing_key { - // Otherwise use the signing key override provided by user - return Ok((None, signing_key.ref_to())); + default: Option
, +) -> Result, Error> { + let signer = if !&args.signing_keys.is_empty() { + let public_keys = + args.signing_keys.iter().map(|key| key.ref_to()).collect(); + return Ok(public_keys); } else if let Some(verification_key) = &args.verification_key { - return Ok((None, verification_key.clone())); - } else if let Some(signer) = &args.signer { - // Otherwise use the signer address provided by user - TxSigningKey::WalletAddress(signer.clone()) + return Ok(vec![verification_key.clone()]); } else { // Otherwise use the signer determined by the caller default }; + // Now actually fetch the signing key and apply it match signer { - TxSigningKey::WalletAddress(signer) if signer == masp() => { - Ok((None, masp_tx_key().ref_to())) - } - TxSigningKey::WalletAddress(signer) => Ok(( - Some(signer.clone()), + Some(signer) if signer == masp() => Ok(vec![masp_tx_key().ref_to()]), + Some(signer) => Ok(vec![ find_pk::(client, wallet, &signer, args.password.clone()) .await?, - )), - TxSigningKey::None => other_err( + ]), + None => other_err( "All transactions must be signed; please either specify the key \ or the address from which to look up the signing key." .to_string(), @@ -207,26 +188,90 @@ 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, + args: &args::Tx, tx: &mut Tx, + signing_data: SigningTxData, +) { + if !args.signatures.is_empty() { + let signatures = args + .signatures + .iter() + .map(|bytes| SignatureIndex::deserialize(bytes).unwrap()) + .collect(); + tx.add_signatures(signatures); + } else if let Some(account_public_keys_map) = + signing_data.account_public_keys_map + { + let signing_tx_keypairs = signing_data + .public_keys + .iter() + .filter_map(|public_key| { + match find_key_by_pk(wallet, args, public_key) { + Ok(secret_key) => Some(secret_key), + Err(_) => None, + } + }) + .collect::>(); + tx.sign_raw(signing_tx_keypairs, account_public_keys_map); + } + + let fee_payer_keypair = + find_key_by_pk(wallet, args, &signing_data.gas_payer).expect(""); + tx.sign_wrapper(fee_payer_keypair); +} + +/// 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, + IO: Io, +>( + client: &C, + wallet: &mut Wallet, args: &args::Tx, - keypair: &common::PublicKey, -) -> Result<(), Error> { - let keypair = find_key_by_pk(wallet, args, keypair)?; - // Sign over the transacttion data - tx.add_section(Section::Signature(Signature::new( - vec![*tx.data_sechash(), *tx.code_sechash()], - &keypair, - ))); - // Remove all the sensitive sections - tx.protocol_filter(); - // Then sign over the bound wrapper - tx.add_section(Section::Signature(Signature::new( - tx.sechashes(), - &keypair, - ))); - Ok(()) + owner: &Option
, + default_signer: Option
, +) -> Result { + let public_keys = if owner.is_some() || args.gas_payer.is_none() { + tx_signers::(client, wallet, args, default_signer.clone()) + .await? + } else { + vec![] + }; + + let (account_public_keys_map, threshold) = match owner { + Some(owner @ Address::Established(_)) => { + let account = rpc::get_account_info::(client, owner).await; + if let Some(account) = account { + (Some(account.public_keys_map), account.threshold) + } else { + return Err(Error::InvalidAccount(owner.encode())); + } + } + Some(Address::Implicit(_)) => ( + Some(AccountPublicKeysMap::from_iter(public_keys.clone())), + 1u8, + ), + Some(owner @ Address::Internal(_)) => { + return Err(Error::InvalidAccount(owner.encode())); + } + None => (None, 0u8), + }; + + let gas_payer = match &args.gas_payer { + Some(keypair) => keypair.ref_to(), + None => public_keys.get(0).ok_or(Error::InvalidFeePayer)?.clone(), + }; + + Ok(SigningTxData { + public_keys, + threshold, + account_public_keys_map, + gas_payer, + }) } #[cfg(not(feature = "mainnet"))] @@ -242,26 +287,26 @@ pub async fn solve_pow_challenge< requires_pow: bool, ) -> (Option, Fee) { let wrapper_tx_fees_key = parameter_storage::get_wrapper_tx_fees_key(); - let fee_amount = rpc::query_storage_value::( + let gas_amount = rpc::query_storage_value::( client, &wrapper_tx_fees_key, ) .await .unwrap_or_default(); - let fee_token = &args.fee_token; + let gas_token = &args.gas_token; let source = Address::from(keypair); - let balance_key = token::balance_key(fee_token, &source); + let balance_key = token::balance_key(gas_token, &source); let balance = rpc::query_storage_value::(client, &balance_key) .await .unwrap_or_default(); - let is_bal_sufficient = fee_amount <= balance; + let is_bal_sufficient = gas_amount <= balance; if !is_bal_sufficient { - let token_addr = args.fee_token.clone(); + let token_addr = args.gas_token.clone(); let err_msg = format!( "The wrapper transaction source doesn't have enough balance to \ pay fee {}, got {}.", - format_denominated_amount::<_, IO>(client, &token_addr, fee_amount) + format_denominated_amount::<_, IO>(client, &token_addr, gas_amount) .await, format_denominated_amount::<_, IO>(client, &token_addr, balance) .await, @@ -271,13 +316,13 @@ pub async fn solve_pow_challenge< } } let fee = Fee { - amount: fee_amount, - token: fee_token.clone(), + amount: gas_amount, + token: gas_token.clone(), }; // A PoW solution can be used to allow zero-fee testnet transactions // If the address derived from the keypair doesn't have enough balance // to pay for the fee, allow to find a PoW solution instead. - if requires_pow || !is_bal_sufficient { + if (requires_pow || !is_bal_sufficient) && !args.dump_tx { display_line!( IO, "The transaction requires the completion of a PoW challenge." @@ -317,215 +362,27 @@ 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, - IO: Io, ->( +pub async fn wrap_tx( client: &C, - #[allow(unused_variables)] wallet: &mut Wallet, + tx: &mut Tx, args: &args::Tx, epoch: Epoch, - mut tx: Tx, - keypair: &common::PublicKey, + gas_payer: common::PublicKey, #[cfg(not(feature = "mainnet"))] requires_pow: bool, -) -> Tx { +) { #[cfg(not(feature = "mainnet"))] let (pow_solution, fee) = - solve_pow_challenge::<_, IO>(client, args, keypair, requires_pow).await; - // This object governs how the payload will be processed - tx.update_header(TxType::Wrapper(Box::new(WrapperTx::new( - fee, - keypair.clone(), - 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::<_, _, IO>(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 -} - -/// 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 sign_wrapper< - C: crate::ledger::queries::Client + Sync, - U: WalletUtils, - IO: Io, ->( - client: &C, - #[allow(unused_variables)] wallet: &mut Wallet, - args: &args::Tx, - epoch: Epoch, - mut tx: Tx, - keypair: &common::SecretKey, - #[cfg(not(feature = "mainnet"))] requires_pow: bool, -) -> TxBroadcastData { - let fee_amount = if cfg!(feature = "mainnet") { - Amount::native_whole(MIN_FEE) - } else { - let wrapper_tx_fees_key = parameter_storage::get_wrapper_tx_fees_key(); - rpc::query_storage_value::( - client, - &wrapper_tx_fees_key, - ) - .await - .unwrap_or_default() - }; - let fee_token = &args.fee_token; - let source = Address::from(&keypair.ref_to()); - let balance_key = token::balance_key(fee_token, &source); - let balance = - rpc::query_storage_value::(client, &balance_key) - .await - .unwrap_or_default(); - let is_bal_sufficient = fee_amount <= balance; - if !is_bal_sufficient { - let token_addr = args.fee_token.clone(); - let err_msg = format!( - "The wrapper transaction source doesn't have enough balance to \ - pay fee {}, got {}.", - format_denominated_amount::<_, IO>(client, &token_addr, fee_amount) - .await, - format_denominated_amount::<_, IO>(client, &token_addr, balance) - .await, - ); - edisplay_line!(IO, "{}", err_msg); - if !args.force && cfg!(feature = "mainnet") { - panic!("{}", err_msg); - } - } - - #[cfg(not(feature = "mainnet"))] - // A PoW solution can be used to allow zero-fee testnet transactions - let pow_solution: Option = { - // If the address derived from the keypair doesn't have enough balance - // to pay for the fee, allow to find a PoW solution instead. - if requires_pow || !is_bal_sufficient { - display_line!( - IO, - "The transaction requires the completion of a PoW challenge." - ); - // Obtain a PoW challenge for faucet withdrawal - let challenge = - rpc::get_testnet_pow_challenge(client, source).await; - - // Solve the solution, this blocks until a solution is found - let solution = challenge.solve(); - Some(solution) - } else { - None - } - }; + solve_pow_challenge::<_, IO>(client, args, &gas_payer, requires_pow) + .await; - // This object governs how the payload will be processed - tx.update_header(TxType::Wrapper(Box::new(WrapperTx::new( - Fee { - amount: fee_amount, - token: fee_token.clone(), - }, - keypair.ref_to(), + tx.add_wrapper( + fee, + gas_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::<_, _, IO>(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"); - } - - // Remove all the sensitive sections - tx.protocol_filter(); - // Then sign over the bound wrapper committing to all other sections - tx.add_section(Section::Signature(Signature::new(tx.sechashes(), keypair))); - // We use this to determine when the wrapper tx makes it on-chain - let wrapper_hash = tx.header_hash().to_string(); - // We use this to determine when the decrypted inner tx makes it - // on-chain - let decrypted_hash = tx - .clone() - .update_header(TxType::Raw) - .header_hash() - .to_string(); - TxBroadcastData::Wrapper { - tx, - wrapper_hash, - decrypted_hash, - } + ); } #[allow(clippy::result_large_err)] @@ -740,6 +597,56 @@ 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, + IO: Io, +>( + 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::<_, _, IO>(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< @@ -770,8 +677,8 @@ pub async fn to_ledger_vector< let reveal_pk_hash = query_wasm_code_hash::<_, IO>(client, TX_REVEAL_PK) .await .unwrap(); - let update_vp_hash = - query_wasm_code_hash::<_, IO>(client, TX_UPDATE_VP_WASM) + let update_account_hash = + query_wasm_code_hash::<_, IO>(client, TX_UPDATE_ACCOUNT_WASM) .await .unwrap(); let transfer_hash = query_wasm_code_hash::<_, IO>(client, TX_TRANSFER_WASM) @@ -851,12 +758,12 @@ pub async fn to_ledger_vector< tv.output.extend(vec![ format!("Type : Init Account"), - format!("Public key : {}", init_account.public_key), + format!("Public key : {:?}", init_account.public_keys), format!("VP type : {}", vp_code), ]); tv.output_expert.extend(vec![ - format!("Public key : {}", init_account.public_key), + format!("Public key : {:?}", init_account.public_keys), format!("VP type : {}", HEXLOWER.encode(&extra.0)), ]); } else if code_hash == init_validator_hash { @@ -881,7 +788,7 @@ pub async fn to_ledger_vector< tv.output.extend(vec![ format!("Type : Init Validator"), - format!("Account key : {}", init_validator.account_key), + format!("Account key : {:?}", init_validator.account_keys), format!("Consensus key : {}", init_validator.consensus_key), format!("Protocol key : {}", init_validator.protocol_key), format!("DKG key : {}", init_validator.dkg_key), @@ -894,7 +801,7 @@ pub async fn to_ledger_vector< ]); tv.output_expert.extend(vec![ - format!("Account key : {}", init_validator.account_key), + format!("Account key : {:?}", init_validator.account_keys), format!("Consensus key : {}", init_validator.consensus_key), format!("Protocol key : {}", init_validator.protocol_key), format!("DKG key : {}", init_validator.dkg_key), @@ -992,36 +899,40 @@ pub async fn to_ledger_vector< tv.output_expert .extend(vec![format!("Public key : {}", public_key)]); - } else if code_hash == update_vp_hash { + } else if code_hash == update_account_hash { let transfer = - UpdateVp::try_from_slice(&tx.data().ok_or_else(|| { + UpdateAccount::try_from_slice(&tx.data().ok_or_else(|| { std::io::Error::from(ErrorKind::InvalidData) })?)?; tv.name = "Update VP 0".to_string(); - let extra = tx - .get_section(&transfer.vp_code_hash) - .and_then(|x| Section::extra_data_sec(x.as_ref())) - .expect("unable to load vp code") - .code - .hash(); - let vp_code = if extra == user_hash { - "User".to_string() - } else { - HEXLOWER.encode(&extra.0) - }; - - tv.output.extend(vec![ - format!("Type : Update VP"), - format!("Address : {}", transfer.addr), - format!("VP type : {}", vp_code), - ]); + match &transfer.vp_code_hash { + Some(hash) => { + let extra = tx + .get_section(hash) + .and_then(|x| Section::extra_data_sec(x.as_ref())) + .expect("unable to load vp code") + .code + .hash(); + let vp_code = if extra == user_hash { + "User".to_string() + } else { + HEXLOWER.encode(&extra.0) + }; + tv.output.extend(vec![ + format!("Type : Update VP"), + format!("Address : {}", transfer.addr), + format!("VP type : {}", vp_code), + ]); - tv.output_expert.extend(vec![ - format!("Address : {}", transfer.addr), - format!("VP type : {}", HEXLOWER.encode(&extra.0)), - ]); + tv.output_expert.extend(vec![ + format!("Address : {}", transfer.addr), + format!("VP type : {}", HEXLOWER.encode(&extra.0)), + ]); + } + None => (), + }; } else if code_hash == transfer_hash { let transfer = Transfer::try_from_slice(&tx.data().ok_or_else(|| { @@ -1070,7 +981,7 @@ pub async fn to_ledger_vector< ) .await; } else if code_hash == ibc_hash { - let msg = Any::decode( + let any_msg = Any::decode( tx.data() .ok_or_else(|| std::io::Error::from(ErrorKind::InvalidData))? .as_ref(), @@ -1080,21 +991,19 @@ pub async fn to_ledger_vector< tv.name = "IBC 0".to_string(); tv.output.push("Type : IBC".to_string()); - match msg.type_url.as_str() { - MSG_TRANSFER_TYPE_URL => { - let transfer = MsgTransfer::try_from(msg).map_err(|_| { - std::io::Error::from(ErrorKind::InvalidData) - })?; + match MsgTransfer::try_from(any_msg.clone()) { + Ok(transfer) => { let transfer_token = format!( "{} {}", - transfer.token.amount, transfer.token.denom + transfer.packet_data.token.amount, + transfer.packet_data.token.denom ); tv.output.extend(vec![ format!("Source port : {}", transfer.port_id_on_a), format!("Source channel : {}", transfer.chan_id_on_a), format!("Token : {}", transfer_token), - format!("Sender : {}", transfer.sender), - format!("Receiver : {}", transfer.receiver), + format!("Sender : {}", transfer.packet_data.sender), + format!("Receiver : {}", transfer.packet_data.receiver), format!( "Timeout height : {}", transfer.timeout_height_on_b @@ -1108,8 +1017,8 @@ pub async fn to_ledger_vector< format!("Source port : {}", transfer.port_id_on_a), format!("Source channel : {}", transfer.chan_id_on_a), format!("Token : {}", transfer_token), - format!("Sender : {}", transfer.sender), - format!("Receiver : {}", transfer.receiver), + format!("Sender : {}", transfer.packet_data.sender), + format!("Receiver : {}", transfer.packet_data.receiver), format!( "Timeout height : {}", transfer.timeout_height_on_b @@ -1121,7 +1030,7 @@ pub async fn to_ledger_vector< ]); } _ => { - for line in format!("{:#?}", msg).split('\n') { + for line in format!("{:#?}", any_msg).split('\n') { let stripped = line.trim_start(); tv.output.push(format!("Part : {}", stripped)); tv.output_expert.push(format!("Part : {}", stripped)); diff --git a/shared/src/ledger/tx.rs b/shared/src/ledger/tx.rs index fabc4e6f40..7ee04652de 100644 --- a/shared/src/ledger/tx.rs +++ b/shared/src/ledger/tx.rs @@ -1,7 +1,7 @@ //! SDK functions to construct different types of transactions use std::borrow::Cow; use std::collections::{BTreeMap, HashMap, HashSet}; -use std::str::FromStr; +use std::fs::File; use std::time::Duration; use borsh::BorshSerialize; @@ -15,32 +15,40 @@ use masp_primitives::transaction::components::transparent::fees::{ InputView as TransparentInputView, OutputView as TransparentOutputView, }; use masp_primitives::transaction::components::Amount; -use namada_core::types::address::{masp, masp_tx_key, Address}; +use namada_core::ledger::governance::cli::onchain::{ + DefaultProposal, PgfFundingProposal, PgfStewardProposal, ProposalVote, +}; +use namada_core::ledger::governance::storage::proposal::ProposalType; +use namada_core::ledger::governance::storage::vote::StorageProposalVote; +use namada_core::types::address::{masp, Address, InternalAddress}; use namada_core::types::dec::Dec; use namada_core::types::token::MaspDenom; +use namada_core::types::transaction::governance::{ + InitProposalData, VoteProposalData, +}; use namada_proof_of_stake::parameters::PosParams; use namada_proof_of_stake::types::{CommissionPair, ValidatorState}; use prost::EncodeError; use thiserror::Error; use super::rpc::query_wasm_code_hash; +use super::signing; use crate::ibc::applications::transfer::msgs::transfer::MsgTransfer; +use crate::ibc::applications::transfer::packet::PacketData; +use crate::ibc::applications::transfer::PrefixedCoin; use crate::ibc::core::ics04_channel::timeout::TimeoutHeight; -use crate::ibc::signer::Signer; -use crate::ibc::timestamp::Timestamp as IbcTimestamp; -use crate::ibc::tx_msg::Msg; +use crate::ibc::core::timestamp::Timestamp as IbcTimestamp; +use crate::ibc::core::Msg; use crate::ibc::Height as IbcHeight; -use crate::ibc_proto::cosmos::base::v1beta1::Coin; use crate::ledger::args::{self, InputAmount}; -use crate::ledger::governance::storage as gov_storage; -use crate::ledger::masp::{ShieldedContext, ShieldedUtils}; +use crate::ledger::ibc::storage::ibc_denom_key; +use crate::ledger::masp::{ShieldedContext, ShieldedTransfer, ShieldedUtils}; use crate::ledger::rpc::{ self, format_denominated_amount, validate_amount, TxBroadcastData, TxResponse, }; -use crate::ledger::signing::{tx_signer, wrap_tx, 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}; @@ -49,7 +57,8 @@ use crate::types::key::*; use crate::types::masp::TransferTarget; use crate::types::storage::Epoch; use crate::types::time::DateTimeUtc; -use crate::types::transaction::{pos, InitAccount, TxType, UpdateVp}; +use crate::types::transaction::account::{InitAccount, UpdateAccount}; +use crate::types::transaction::{pos, TxType}; use crate::types::{storage, token}; use crate::vm::WasmValidationError; use crate::{display_line, edisplay_line, vm}; @@ -65,7 +74,7 @@ pub const TX_VOTE_PROPOSAL: &str = "tx_vote_proposal.wasm"; /// Reveal public key transaction WASM path pub const TX_REVEAL_PK: &str = "tx_reveal_pk.wasm"; /// Update validity predicate WASM path -pub const TX_UPDATE_VP_WASM: &str = "tx_update_vp.wasm"; +pub const TX_UPDATE_ACCOUNT_WASM: &str = "tx_update_account.wasm"; /// Transfer transaction WASM path pub const TX_TRANSFER_WASM: &str = "tx_transfer.wasm"; /// IBC transaction WASM path @@ -198,6 +207,21 @@ pub enum Error { /// Like EncodeTxFailure but for the encode error type #[error("Encoding tx data, {0}, shouldn't fail")] EncodeFailure(EncodeError), + /// Failed to deserialize the proposal data from json + #[error("Failed to deserialize the proposal data: {0}")] + FailedGovernaneProposalDeserialize(String), + /// The proposal data are invalid + #[error("Proposal data are invalid: {0}")] + InvalidProposal(String), + /// The proposal vote is not valid + #[error("Proposal vote is invalid")] + InvalidProposalVote, + /// The proposal can't be voted + #[error("Proposal {0} can't be voted")] + InvalidProposalVotingPeriod(u64), + /// The proposal can't be found + #[error("Proposal {0} can't be found")] + ProposalDoesNotExist(u64), /// Encoding public key failure #[error("Encoding a public key, {0}, shouldn't fail")] EncodeKeyFailure(std::io::Error), @@ -221,6 +245,18 @@ pub enum Error { /// Epoch not in storage #[error("Proposal end epoch is not in the storage.")] EpochNotInStorage, + /// Couldn't understand who the fee payer is + #[error("Either --signing-keys or --gas-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), @@ -234,6 +270,8 @@ pub enum ProcessTxResponse { Broadcast(Response), /// Result of dry running transaction DryRun, + /// Dump transaction to disk + Dump, } impl ProcessTxResponse { @@ -246,42 +284,42 @@ impl ProcessTxResponse { } } +/// Build and dump a transaction either to file or to screen +pub fn dump_tx(args: &args::Tx, tx: Tx) { + 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 => display_line!(IO, "{}", 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, - IO: Io, ->( +pub async fn prepare_tx( client: &C, - wallet: &mut Wallet, args: &args::Tx, - tx: Tx, - default_signer: TxSigningKey, + tx: &mut Tx, + gas_payer: common::PublicKey, #[cfg(not(feature = "mainnet"))] requires_pow: bool, -) -> Result<(Tx, Option
, common::PublicKey), Error> { - let (signer_addr, signer_pk) = - tx_signer::(client, wallet, args, default_signer.clone()) - .await?; - if args.dry_run { - Ok((tx, signer_addr, signer_pk)) - } else { +) { + if !args.dry_run { let epoch = rpc::query_epoch(client).await; - Ok(( - wrap_tx::<_, _, IO>( - client, - wallet, - args, - epoch, - tx.clone(), - &signer_pk, - #[cfg(not(feature = "mainnet"))] - requires_pow, - ) - .await, - signer_addr, - signer_pk, - )) + signing::wrap_tx::<_, IO>( + client, + tx, + args, + epoch, + gas_payer, + #[cfg(not(feature = "mainnet"))] + requires_pow, + ) + .await } } @@ -295,10 +333,8 @@ pub async fn process_tx< client: &C, wallet: &mut Wallet, args: &args::Tx, - mut tx: Tx, + tx: Tx, ) -> Result { - // Remove all the sensitive sections - tx.protocol_filter(); // NOTE: use this to print the request JSON body: // let request = @@ -349,77 +385,42 @@ 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, - IO: Io, ->( - client: &C, - wallet: &mut Wallet, - args: args::RevealPk, -) -> Result, common::PublicKey)>, 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(); - display_line!(IO, "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, ->( +/// Check if a reveal public key transaction is needed +pub async fn is_reveal_pk_needed( 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::get_public_key(client, addr).await.is_some() + 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, IO: Io, >( client: &C, - wallet: &mut Wallet, - public_key: &common::PublicKey, args: &args::Tx, -) -> Result<(Tx, Option
, common::PublicKey), Error> { - let addr: Address = public_key.into(); + address: &Address, + public_key: &common::PublicKey, + gas_payer: &common::PublicKey, +) -> Result { display_line!( IO, - "Submitting a tx to reveal the public key for address {addr}..." + "Submitting a tx to reveal the public key for address {address}..." ); - let tx_data = public_key.try_to_vec().map_err(Error::EncodeKeyFailure)?; let tx_code_hash = query_wasm_code_hash::<_, IO>( client, @@ -428,22 +429,21 @@ 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 mut tx = Tx::new(chain_id, args.expiration); + tx.add_code_from_hash(tx_code_hash).add_data(public_key); - prepare_tx::( + prepare_tx::( client, - wallet, args, - tx, - TxSigningKey::WalletAddress(addr), + &mut tx, + gas_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) - .await + .await; + Ok(tx) } /// Broadcast a transaction to be included in the blockchain and checks that @@ -661,33 +661,35 @@ 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, IO: Io, >( client: &C, - wallet: &mut Wallet, - args: args::CommissionRateChange, -) -> Result<(Tx, Option
, common::PublicKey), Error> { + args::CommissionRateChange { + tx: tx_args, + validator, + rate, + tx_code_path, + }: args::CommissionRateChange, + gas_payer: &common::PublicKey, +) -> Result { let epoch = rpc::query_epoch(client).await; - let tx_code_hash = query_wasm_code_hash::<_, IO>( - client, - args.tx_code_path.to_str().unwrap(), - ) - .await - .unwrap(); + let tx_code_hash = + query_wasm_code_hash::<_, IO>(client, tx_code_path.to_str().unwrap()) + .await + .unwrap(); let params: PosParams = rpc::get_pos_params(client).await; - 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() { + if rate < Dec::zero() || rate > Dec::one() { edisplay_line!( IO, "Invalid new commission rate, received {}", - args.rate + rate ); - return Err(Error::InvalidCommissionRate(args.rate)); + return Err(Error::InvalidCommissionRate(rate)); } let pipeline_epoch_minus_one = epoch + params.pipeline_len - 1; @@ -703,7 +705,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 { edisplay_line!( @@ -712,121 +714,67 @@ 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_args.force { + return Err(Error::InvalidCommissionRate(rate)); } } } None => { edisplay_line!(IO, "Error retrieving from storage"); - if !args.tx.force { + if !tx_args.force { return Err(Error::Retrieval); } } } } else { edisplay_line!(IO, "The given address {validator} is not a validator."); - if !args.tx.force { + if !tx_args.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_args.chain_id.clone().unwrap(); + let mut tx = Tx::new(chain_id, tx_args.expiration); + tx.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, - TxSigningKey::WalletAddress(default_signer), + &tx_args, + &mut tx, + gas_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) - .await + .await; + Ok(tx) } /// Submit transaction to unjail a jailed validator pub async fn build_unjail_validator< C: crate::ledger::queries::Client + Sync, - U: WalletUtils, IO: Io, >( client: &C, - wallet: &mut Wallet, - args: args::TxUnjailValidator, -) -> Result<(Tx, Option
, common::PublicKey), Error> { - if !rpc::is_validator(client, &args.validator).await { - edisplay_line!( - IO, - "The given address {} is not a validator.", - &args.validator - ); - if !args.tx.force { - return Err(Error::InvalidValidatorAddress(args.validator.clone())); - } - } - - let tx_code_hash = query_wasm_code_hash::<_, IO>( - client, - args.tx_code_path.to_str().unwrap(), - ) - .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::<_, _, IO>( - client, - wallet, - &args.tx, - tx, - 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, - IO: Io, ->( - client: &C, - wallet: &mut Wallet, - args: args::TxUnjailValidator, -) -> Result<(), Error> { - if !rpc::is_validator(client, &args.validator).await { + args::TxUnjailValidator { + tx: tx_args, + validator, + tx_code_path, + }: args::TxUnjailValidator, + gas_payer: &common::PublicKey, +) -> Result { + if !rpc::is_validator(client, &validator).await { edisplay_line!( IO, "The given address {} is not a validator.", - &args.validator + &validator ); - if !args.tx.force { - return Err(Error::InvalidValidatorAddress(args.validator.clone())); + if !tx_args.force { + return Err(Error::InvalidValidatorAddress(validator.clone())); } } @@ -835,7 +783,7 @@ pub async fn submit_unjail_validator< let pipeline_epoch = current_epoch + params.pipeline_len; let validator_state_at_pipeline = - rpc::get_validator_state(client, &args.validator, Some(pipeline_epoch)) + rpc::get_validator_state(client, &validator, Some(pipeline_epoch)) .await .expect("Validator state should be defined."); if validator_state_at_pipeline != ValidatorState::Jailed { @@ -843,17 +791,15 @@ pub async fn submit_unjail_validator< IO, "The given validator address {} is not jailed at the pipeline \ epoch when it would be restored to one of the validator sets.", - &args.validator + &validator ); - if !args.tx.force { - return Err(Error::ValidatorNotCurrentlyJailed( - args.validator.clone(), - )); + if !tx_args.force { + return Err(Error::ValidatorNotCurrentlyJailed(validator.clone())); } } let last_slash_epoch_key = - crate::ledger::pos::validator_last_slash_key(&args.validator); + crate::ledger::pos::validator_last_slash_key(&validator); let last_slash_epoch = rpc::query_storage_value::(client, &last_slash_epoch_key) .await; @@ -865,76 +811,72 @@ pub async fn submit_unjail_validator< IO, "The given validator address {} is currently frozen and not \ yet eligible to be unjailed.", - &args.validator + &validator ); - if !args.tx.force { + if !tx_args.force { return Err(Error::ValidatorNotCurrentlyJailed( - args.validator.clone(), + validator.clone(), )); } } } - let tx_code_hash = query_wasm_code_hash::<_, IO>( - client, - args.tx_code_path.to_str().unwrap(), - ) - .await - .unwrap(); + let tx_code_hash = + query_wasm_code_hash::<_, IO>(client, tx_code_path.to_str().unwrap()) + .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_args.chain_id.clone().unwrap(); + let mut tx = Tx::new(chain_id, tx_args.expiration); + tx.add_code_from_hash(tx_code_hash) + .add_data(validator.clone()); - let default_signer = args.validator; - prepare_tx::<_, _, IO>( + prepare_tx::<_, IO>( client, - wallet, - &args.tx, - tx, - TxSigningKey::WalletAddress(default_signer), + &tx_args, + &mut tx, + gas_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) - .await?; - Ok(()) + .await; + Ok(tx) } /// Submit transaction to withdraw an unbond pub async fn build_withdraw< C: crate::ledger::queries::Client + Sync, - U: WalletUtils, IO: Io, >( client: &C, - wallet: &mut Wallet, - args: args::Withdraw, -) -> Result<(Tx, Option
, common::PublicKey), Error> { + args::Withdraw { + tx: tx_args, + validator, + source, + tx_code_path, + }: args::Withdraw, + gas_payer: &common::PublicKey, +) -> Result { let epoch = rpc::query_epoch(client).await; let validator = known_validator_or_err::<_, IO>( - args.validator.clone(), - args.tx.force, + validator.clone(), + tx_args.force, client, ) .await?; - let source = args.source.clone(); + let source = source.clone(); - let tx_code_hash = query_wasm_code_hash::<_, IO>( - client, - args.tx_code_path.to_str().unwrap(), - ) - .await - .unwrap(); + let tx_code_hash = + query_wasm_code_hash::<_, IO>(client, tx_code_path.to_str().unwrap()) + .await + .unwrap(); // Check the source's current unbond amount let bond_source = source.clone().unwrap_or_else(|| validator.clone()); @@ -945,6 +887,7 @@ pub async fn build_withdraw< Some(epoch), ) .await; + if tokens.is_zero() { edisplay_line!( IO, @@ -954,7 +897,7 @@ pub async fn build_withdraw< ); rpc::query_and_print_unbonds::<_, IO>(client, &bond_source, &validator) .await; - if !args.tx.force { + if !tx_args.force { return Err(Error::NoUnbondReady(epoch)); } } else { @@ -967,25 +910,21 @@ 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_args.chain_id.clone().unwrap(); + let mut tx = Tx::new(chain_id, tx_args.expiration); + tx.add_code_from_hash(tx_code_hash).add_data(data); - let default_signer = args.source.unwrap_or(args.validator); - prepare_tx::( + prepare_tx::( client, - wallet, - &args.tx, - tx, - TxSigningKey::WalletAddress(default_signer), + &tx_args, + &mut tx, + gas_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) - .await + .await; + Ok(tx) } /// Submit a transaction to unbond @@ -995,58 +934,55 @@ pub async fn build_unbond< IO: Io, >( client: &C, - wallet: &mut Wallet, - args: args::Unbond, -) -> Result< - ( - Tx, - Option
, - common::PublicKey, - Option<(Epoch, token::Amount)>, - ), - Error, -> { - let source = args.source.clone(); + _wallet: &mut Wallet, + args::Unbond { + tx: tx_args, + validator, + amount, + source, + tx_code_path, + }: args::Unbond, + gas_payer: &common::PublicKey, +) -> Result<(Tx, 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::<_, IO>( - client, - args.tx_code_path.to_str().unwrap(), - ) - .await - .unwrap(); + let tx_code_hash = + query_wasm_code_hash::<_, IO>(client, tx_code_path.to_str().unwrap()) + .await + .unwrap(); - if !args.tx.force { + if !tx_args.force { known_validator_or_err::<_, IO>( - args.validator.clone(), - args.tx.force, + validator.clone(), + tx_args.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; display_line!( IO, "Bond amount available for unbonding: {} NAM", bond_amount.to_string_native() ); - if args.amount > bond_amount { + if amount > bond_amount { edisplay_line!( IO, "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_args.force { return Err(Error::LowerBondThanUnbond( bond_source, - args.amount.to_string_native(), + amount.to_string_native(), bond_amount.to_string_native(), )); } @@ -1055,8 +991,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(); @@ -1065,31 +1000,26 @@ 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_args.chain_id.clone().unwrap(); + let mut tx = Tx::new(chain_id, tx_args.expiration); + tx.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, default_signer) = prepare_tx::( + prepare_tx::( client, - wallet, - &args.tx, - tx, - TxSigningKey::WalletAddress(default_signer), + &tx_args, + &mut tx, + gas_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) - .await?; + .await; - Ok((tx, signer_addr, default_signer, latest_withdrawal_pre)) + Ok((tx, latest_withdrawal_pre)) } /// Query the unbonds post-tx @@ -1159,27 +1089,30 @@ pub async fn query_unbonds( } /// Submit a transaction to bond -pub async fn build_bond< - C: crate::ledger::queries::Client + Sync, - U: WalletUtils, - IO: Io, ->( +pub async fn build_bond( client: &C, - wallet: &mut Wallet, - args: args::Bond, -) -> Result<(Tx, Option
, common::PublicKey), Error> { + args::Bond { + tx: tx_args, + validator, + amount, + source, + native_token, + tx_code_path, + }: args::Bond, + gas_payer: &common::PublicKey, +) -> Result { let validator = known_validator_or_err::<_, IO>( - args.validator.clone(), - args.tx.force, + validator.clone(), + tx_args.force, client, ) .await?; // Check that the source address exists on chain - let source = args.source.clone(); - let source = match args.source.clone() { + let source = source.clone(); + let source = match source.clone() { Some(source) => { - source_exists_or_err::<_, IO>(source, args.tx.force, client) + source_exists_or_err::<_, IO>(source, tx_args.force, client) .await .map(Some) } @@ -1188,137 +1121,362 @@ 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::<_, IO>( - &args.native_token, + &native_token, bond_source, - args.amount, + amount, balance_key, - args.tx.force, + tx_args.force, client, ) .await?; - let tx_code_hash = query_wasm_code_hash::<_, IO>( - client, - args.tx_code_path.to_str().unwrap(), - ) - .await - .unwrap(); + let tx_code_hash = + query_wasm_code_hash::<_, IO>(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_args.chain_id.clone().unwrap(); + let mut tx = Tx::new(chain_id, tx_args.expiration); + tx.add_code_from_hash(tx_code_hash).add_data(data); - let default_signer = args.source.unwrap_or(args.validator); - prepare_tx::( + prepare_tx::( client, - wallet, - &args.tx, + &tx_args, + &mut tx, + gas_payer.clone(), + #[cfg(not(feature = "mainnet"))] + false, + ) + .await; + Ok(tx) +} + +/// Build a default proposal governance +pub async fn build_default_proposal< + C: crate::ledger::queries::Client + Sync, + IO: Io, +>( + client: &C, + args::InitProposal { tx, - TxSigningKey::WalletAddress(default_signer), + proposal_data: _, + native_token: _, + is_offline: _, + is_pgf_stewards: _, + is_pgf_funding: _, + tx_code_path, + }: args::InitProposal, + proposal: DefaultProposal, + gas_payer: &common::PublicKey, +) -> Result { + let mut init_proposal_data = + InitProposalData::try_from(proposal.clone()) + .map_err(|e| Error::InvalidProposal(e.to_string()))?; + + let tx_code_hash = + query_wasm_code_hash::<_, IO>(client, tx_code_path.to_str().unwrap()) + .await + .unwrap(); + + let chain_id = tx.chain_id.clone().unwrap(); + + let mut tx_builder = Tx::new(chain_id, tx.expiration); + + let (_, extra_section_hash) = tx_builder + .add_extra_section(proposal.proposal.content.try_to_vec().unwrap()); + init_proposal_data.content = extra_section_hash; + + if let Some(init_proposal_code) = proposal.data { + let (_, extra_section_hash) = + tx_builder.add_extra_section(init_proposal_code); + init_proposal_data.r#type = + ProposalType::Default(Some(extra_section_hash)); + }; + + tx_builder + .add_code_from_hash(tx_code_hash) + .add_data(init_proposal_data); + + prepare_tx::( + client, + &tx, + &mut tx_builder, + gas_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) - .await + .await; + + Ok(tx_builder) } -/// Check if current epoch is in the last third of the voting period of the -/// proposal. This ensures that it is safe to optimize the vote writing to -/// storage. -pub async fn is_safe_voting_window( +/// Build a proposal vote +pub async fn build_vote_proposal< + C: crate::ledger::queries::Client + Sync, + IO: Io, +>( client: &C, - proposal_id: u64, - proposal_start_epoch: Epoch, -) -> Result { - let current_epoch = rpc::query_epoch(client).await; + args::VoteProposal { + tx, + proposal_id, + vote, + voter, + is_offline: _, + proposal_data: _, + tx_code_path, + }: args::VoteProposal, + epoch: Epoch, + gas_payer: &common::PublicKey, +) -> Result { + let proposal_vote = + ProposalVote::try_from(vote).map_err(|_| Error::InvalidProposalVote)?; + + let proposal_id = proposal_id.expect("Proposal id must be defined."); + let proposal = if let Some(proposal) = + rpc::query_proposal_by_id(client, proposal_id).await + { + proposal + } else { + return Err(Error::ProposalDoesNotExist(proposal_id)); + }; - let proposal_end_epoch_key = - gov_storage::get_voting_end_epoch_key(proposal_id); - let proposal_end_epoch = - rpc::query_storage_value::(client, &proposal_end_epoch_key) - .await; + let storage_vote = + StorageProposalVote::build(&proposal_vote, &proposal.r#type) + .expect("Should be able to build the proposal vote"); - match proposal_end_epoch { - Some(proposal_end_epoch) => { - Ok(!crate::ledger::native_vp::governance::utils::is_valid_validator_voting_period( - current_epoch, - proposal_start_epoch, - proposal_end_epoch, - )) - } - None => { - Err(Error::EpochNotInStorage) - } + let is_validator = rpc::is_validator(client, &voter).await; + + if !proposal.can_be_voted(epoch, is_validator) { + return Err(Error::InvalidProposalVotingPeriod(proposal_id)); } + + let delegations = rpc::get_delegators_delegation_at( + client, + &voter, + proposal.voting_start_epoch, + ) + .await + .keys() + .cloned() + .collect::>(); + + let data = VoteProposalData { + id: proposal_id, + vote: storage_vote, + voter: voter.clone(), + delegations, + }; + + let tx_code_hash = + query_wasm_code_hash::<_, IO>(client, tx_code_path.to_str().unwrap()) + .await + .unwrap(); + + let chain_id = tx.chain_id.clone().unwrap(); + + let mut tx_builder = Tx::new(chain_id, tx.expiration); + tx_builder.add_code_from_hash(tx_code_hash).add_data(data); + + prepare_tx::( + client, + &tx, + &mut tx_builder, + gas_payer.clone(), + #[cfg(not(feature = "mainnet"))] + false, + ) + .await; + + Ok(tx_builder) +} + +/// Build a pgf funding proposal governance +pub async fn build_pgf_funding_proposal< + C: crate::ledger::queries::Client + Sync, + IO: Io, +>( + client: &C, + args::InitProposal { + tx, + proposal_data: _, + native_token: _, + is_offline: _, + is_pgf_stewards: _, + is_pgf_funding: _, + tx_code_path, + }: args::InitProposal, + proposal: PgfFundingProposal, + gas_payer: &common::PublicKey, +) -> Result { + let mut init_proposal_data = + InitProposalData::try_from(proposal.clone()) + .map_err(|e| Error::InvalidProposal(e.to_string()))?; + + let tx_code_hash = + query_wasm_code_hash::<_, IO>(client, tx_code_path.to_str().unwrap()) + .await + .unwrap(); + + let chain_id = tx.chain_id.clone().unwrap(); + + let mut tx_builder = Tx::new(chain_id, tx.expiration); + + let (_, extra_section_hash) = tx_builder + .add_extra_section(proposal.proposal.content.try_to_vec().unwrap()); + init_proposal_data.content = extra_section_hash; + + tx_builder + .add_code_from_hash(tx_code_hash) + .add_data(init_proposal_data); + + prepare_tx::( + client, + &tx, + &mut tx_builder, + gas_payer.clone(), + #[cfg(not(feature = "mainnet"))] + false, + ) + .await; + + Ok(tx_builder) +} + +/// Build a pgf funding proposal governance +pub async fn build_pgf_stewards_proposal< + C: crate::ledger::queries::Client + Sync, + IO: Io, +>( + client: &C, + args::InitProposal { + tx, + proposal_data: _, + native_token: _, + is_offline: _, + is_pgf_stewards: _, + is_pgf_funding: _, + tx_code_path, + }: args::InitProposal, + proposal: PgfStewardProposal, + gas_payer: &common::PublicKey, +) -> Result { + let mut init_proposal_data = + InitProposalData::try_from(proposal.clone()) + .map_err(|e| Error::InvalidProposal(e.to_string()))?; + + let tx_code_hash = + query_wasm_code_hash::<_, IO>(client, tx_code_path.to_str().unwrap()) + .await + .unwrap(); + + let chain_id = tx.chain_id.clone().unwrap(); + + let mut tx_builder = Tx::new(chain_id, tx.expiration); + + let (_, extra_section_hash) = tx_builder + .add_extra_section(proposal.proposal.content.try_to_vec().unwrap()); + init_proposal_data.content = extra_section_hash; + + tx_builder + .add_code_from_hash(tx_code_hash) + .add_data(init_proposal_data); + + prepare_tx::( + client, + &tx, + &mut tx_builder, + gas_payer.clone(), + #[cfg(not(feature = "mainnet"))] + false, + ) + .await; + + Ok(tx_builder) } /// Submit an IBC transfer pub async fn build_ibc_transfer< C: crate::ledger::queries::Client + Sync, - U: WalletUtils, IO: Io, >( client: &C, - wallet: &mut Wallet, - args: args::TxIbcTransfer, -) -> Result<(Tx, Option
, common::PublicKey), Error> { + args::TxIbcTransfer { + tx: tx_args, + source, + receiver, + token, + amount, + port_id, + channel_id, + timeout_height, + timeout_sec_offset, + memo, + tx_code_path, + }: args::TxIbcTransfer, + gas_payer: &common::PublicKey, +) -> Result { // Check that the source address exists on chain - let source = source_exists_or_err::<_, IO>( - args.source.clone(), - args.tx.force, - client, - ) - .await?; + let source = + source_exists_or_err::<_, IO>(source.clone(), tx_args.force, client) + .await?; // We cannot check the receiver - let token = args.token; - // Check source balance let balance_key = token::balance_key(&token, &source); check_balance_too_low_err::<_, IO>( &token, &source, - args.amount, + amount, balance_key, - args.tx.force, + tx_args.force, client, ) .await?; - let tx_code_hash = query_wasm_code_hash::<_, IO>( - client, - args.tx_code_path.to_str().unwrap(), - ) - .await - .unwrap(); + let tx_code_hash = + query_wasm_code_hash::<_, IO>(client, tx_code_path.to_str().unwrap()) + .await + .unwrap(); - let amount = args - .amount + let ibc_denom = match &token { + Address::Internal(InternalAddress::IbcToken(hash)) => { + let ibc_denom_key = ibc_denom_key(hash); + rpc::query_storage_value::(client, &ibc_denom_key) + .await + .ok_or_else(|| Error::TokenDoesNotExist(token.clone()))? + } + _ => token.to_string(), + }; + let amount = amount .to_string_native() .split('.') .next() .expect("invalid amount") .to_string(); - let token = Coin { - denom: token.to_string(), - amount, + let token = PrefixedCoin { + denom: ibc_denom.parse().expect("Invalid IBC denom"), + amount: amount.parse().expect("Invalid amount"), + }; + let packet_data = PacketData { + token, + sender: source.to_string().into(), + receiver: receiver.into(), + memo: memo.unwrap_or_default().into(), }; // 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")) } @@ -1327,7 +1485,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 @@ -1337,36 +1495,33 @@ pub async fn build_ibc_transfer< }; let msg = MsgTransfer { - port_id_on_a: args.port_id, - chan_id_on_a: args.channel_id, - token, - sender: Signer::from_str(&source.to_string()).expect("invalid signer"), - receiver: Signer::from_str(&args.receiver).expect("invalid signer"), + port_id_on_a: port_id, + chan_id_on_a: channel_id, + packet_data, 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_args.chain_id.clone().unwrap(); + let mut tx = Tx::new(chain_id, tx_args.expiration); + tx.add_code_from_hash(tx_code_hash) + .add_serialized_data(data); - prepare_tx::( + prepare_tx::( client, - wallet, - &args.tx, - tx, - TxSigningKey::WalletAddress(args.source), + &tx_args, + &mut tx, + gas_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) - .await + .await; + Ok(tx) } /// Try to decode the given asset type and add its decoding to the supplied set. @@ -1445,16 +1600,14 @@ async fn used_asset_types< /// Submit an ordinary transfer pub async fn build_transfer< C: crate::ledger::queries::Client + Sync, - V: WalletUtils, U: ShieldedUtils, IO: Io, >( client: &C, - wallet: &mut Wallet, shielded: &mut ShieldedContext, mut args: args::TxTransfer, -) -> Result<(Tx, Option
, common::PublicKey, Option, bool), Error> -{ + gas_payer: &common::PublicKey, +) -> Result<(Tx, Option), Error> { let source = args.source.effective_address(); let target = args.target.effective_address(); let token = args.token.clone(); @@ -1475,16 +1628,15 @@ pub async fn build_transfer< .expect("expected to validate amount"); let validate_fee = validate_amount::<_, IO>( client, - args.tx.fee_amount, - &args.tx.fee_token, + args.tx.gas_amount, + &args.tx.gas_token, args.tx.force, ) .await .expect("expected to be able to validate fee"); args.amount = InputAmount::Validated(validated_amount); - args.tx.fee_amount = InputAmount::Validated(validate_fee); - + args.tx.gas_amount = InputAmount::Validated(validate_fee); check_balance_too_low_err::( &token, &source, @@ -1500,21 +1652,14 @@ pub async fn build_transfer< // signer. Also, if the transaction is shielded, redact the amount and token // types by setting the transparent value to 0 and token type to a constant. // This has no side-effect because transaction is to self. - let (_amount, token) = if source == masp_addr && target == masp_addr { - // TODO Refactor me, we shouldn't rely on any specific token here. - (token::Amount::default(), args.native_token.clone()) - } else { - (validated_amount.amount, token) - }; - let default_signer = - TxSigningKey::WalletAddress(args.source.effective_address()); - // If our chosen signer is the MASP sentinel key, then our shielded inputs - // will need to cover the gas fees. - let chosen_signer = - tx_signer::(client, wallet, &args.tx, default_signer.clone()) - .await? - .1; - let shielded_gas = masp_tx_key().ref_to() == chosen_signer; + let (_amount, token, shielded_gas) = + if source == masp_addr && target == masp_addr { + // TODO Refactor me, we shouldn't rely on any specific token here. + (token::Amount::default(), args.native_token.clone(), true) + } else { + (validated_amount.amount, token, false) + }; + // Determine whether to pin this transaction to a storage key let key = match &args.target { TransferTarget::PaymentAddress(pa) if pa.is_pinned() => Some(pa.hash()), @@ -1523,6 +1668,8 @@ pub async fn build_transfer< #[cfg(not(feature = "mainnet"))] let is_source_faucet = rpc::is_faucet_account(client, &source).await; + #[cfg(feature = "mainnet")] + let is_source_faucet = false; let tx_code_hash = query_wasm_code_hash::<_, IO>( client, @@ -1544,40 +1691,44 @@ pub async fn build_transfer< validated_amount.amount.to_string_native(), Box::new(token.clone()), validate_fee.amount.to_string_native(), - Box::new(args.tx.fee_token.clone()), + Box::new(args.tx.gas_token.clone()), )) } 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 mut tx = Tx::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 + let (masp_hash, shielded_tx_epoch) = if let Some(ShieldedTransfer { + builder, + masp_tx, + metadata, + epoch, + }) = 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(); + // Add a MASP Transaction section to the Tx and get the tx hash + let masp_tx_hash = tx.add_masp_tx_section(masp_tx).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) + let asset_types = used_asset_types(shielded, client, &builder) .await .unwrap_or_default(); - // Add the MASP Transaction's Builder to the Tx - tx.add_section(Section::MaspBuilder(MaspBuilder { + + tx.add_masp_builder(MaspBuilder { asset_types, // Store how the Info objects map to Descriptors/Outputs - metadata: shielded_parts.2, + metadata, // Store the data that was used to construct the Transaction - builder: shielded_parts.0, + builder, // Link the Builder to the Transaction by hash code - target: masp_hash, - })); + target: masp_tx_hash, + }); + // The MASP Transaction section hash will be used in Transfer - (Some(masp_hash), Some(shielded_parts.3)) + (Some(masp_tx_hash), Some(epoch)) } else { (None, None) }; @@ -1591,209 +1742,192 @@ pub async fn build_transfer< // Link the Transfer to the MASP Transaction by hash code shielded: masp_hash, }; + 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)); + + tx.add_code_from_hash(tx_code_hash).add_data(transfer); // Dry-run/broadcast/submit the transaction - let (tx, signer_addr, def_key) = prepare_tx::( + prepare_tx::( client, - wallet, &args.tx, - tx, - default_signer.clone(), + &mut tx, + gas_payer.clone(), #[cfg(not(feature = "mainnet"))] is_source_faucet, ) - .await?; - Ok(( - tx, - signer_addr, - def_key, - shielded_tx_epoch, - is_source_faucet, - )) + .await; + + Ok((tx, shielded_tx_epoch)) } /// Submit a transaction to initialize an account pub async fn build_init_account< C: crate::ledger::queries::Client + Sync, - U: WalletUtils, IO: Io, >( client: &C, - wallet: &mut Wallet, - args: args::TxInitAccount, -) -> Result<(Tx, Option
, common::PublicKey), Error> { - let public_key = args.public_key; + args::TxInitAccount { + tx: tx_args, + vp_code_path, + tx_code_path, + public_keys, + threshold, + }: args::TxInitAccount, + gas_payer: &common::PublicKey, +) -> Result { + let vp_code_hash = + query_wasm_code_hash::<_, IO>(client, vp_code_path.to_str().unwrap()) + .await + .unwrap(); - let vp_code_hash = query_wasm_code_hash::<_, IO>( - client, - args.vp_code_path.to_str().unwrap(), - ) - .await - .unwrap(); + let tx_code_hash = + query_wasm_code_hash::<_, IO>(client, tx_code_path.to_str().unwrap()) + .await + .unwrap(); - let tx_code_hash = query_wasm_code_hash::<_, IO>( - client, - args.tx_code_path.to_str().unwrap(), - ) - .await - .unwrap(); + let threshold = match threshold { + Some(threshold) => threshold, + None => { + if public_keys.len() == 1 { + 1u8 + } else { + return Err(Error::MissingAccountThreshold); + } + } + }; - 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_args.chain_id.clone().unwrap(); + let mut tx = Tx::new(chain_id, tx_args.expiration); + let extra_section_hash = tx.add_extra_section_from_hash(vp_code_hash); let data = InitAccount { - public_key, - vp_code_hash: extra.get_hash(), + public_keys, + 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)); + tx.add_code_from_hash(tx_code_hash).add_data(data); - prepare_tx::( + prepare_tx::( client, - wallet, - &args.tx, - tx, - TxSigningKey::WalletAddress(args.source), + &tx_args, + &mut tx, + gas_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) - .await + .await; + Ok(tx) } /// Submit a transaction to update a VP -pub async fn build_update_vp< +pub async fn build_update_account< C: crate::ledger::queries::Client + Sync, - U: WalletUtils, IO: Io, >( client: &C, - wallet: &mut Wallet, - args: args::TxUpdateVp, -) -> Result<(Tx, Option
, common::PublicKey), 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 { - edisplay_line!( - IO, - "The address {} doesn't exist on chain.", - addr - ); - Ok(()) - } else { - Err(Error::LocationDoesNotExist(addr.clone())) - } - } else { - Ok(()) - } - } - Address::Implicit(_) => { - if args.tx.force { - edisplay_line!( - IO, - "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 { - edisplay_line!( - IO, - "A validity predicate of an internal address cannot be \ - directly updated." - ); - Ok(()) - } else { - Err(Error::ImplicitInternalError) - } + args::TxUpdateAccount { + tx: tx_args, + vp_code_path, + tx_code_path, + addr, + public_keys, + threshold, + }: args::TxUpdateAccount, + gas_payer: &common::PublicKey, +) -> Result { + let addr = if let Some(account) = rpc::get_account_info(client, &addr).await + { + account.address + } else if tx_args.force { + addr + } else { + return Err(Error::LocationDoesNotExist(addr)); + }; + + let vp_code_hash = match vp_code_path { + Some(code_path) => { + let vp_hash = query_wasm_code_hash::<_, IO>( + client, + code_path.to_str().unwrap(), + ) + .await + .unwrap(); + Some(vp_hash) } - }?; + None => None, + }; - let vp_code_hash = query_wasm_code_hash::<_, IO>( - client, - args.vp_code_path.to_str().unwrap(), - ) - .await - .unwrap(); + let tx_code_hash = + query_wasm_code_hash::<_, IO>(client, tx_code_path.to_str().unwrap()) + .await + .unwrap(); - let tx_code_hash = query_wasm_code_hash::<_, IO>( - client, - args.tx_code_path.to_str().unwrap(), - ) - .await - .unwrap(); + let chain_id = tx_args.chain_id.clone().unwrap(); + let mut tx = Tx::new(chain_id, tx_args.expiration); + let extra_section_hash = vp_code_hash + .map(|vp_code_hash| tx.add_extra_section_from_hash(vp_code_hash)); - 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 data = UpdateVp { + let data = UpdateAccount { addr, - vp_code_hash: extra.get_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)); - prepare_tx::( + tx.add_code_from_hash(tx_code_hash).add_data(data); + + prepare_tx::( client, - wallet, - &args.tx, - tx, - TxSigningKey::WalletAddress(args.addr), + &tx_args, + &mut tx, + gas_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) - .await + .await; + Ok(tx) } /// Submit a custom transaction -pub async fn build_custom< - C: crate::ledger::queries::Client + Sync, - U: WalletUtils, - IO: Io, ->( +pub async fn build_custom( client: &C, - wallet: &mut Wallet, - args: args::TxCustom, -) -> Result<(Tx, Option
, common::PublicKey), 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)); - - prepare_tx::( + args::TxCustom { + tx: tx_args, + code_path, + data_path, + serialized_tx, + owner: _, + }: args::TxCustom, + gas_payer: &common::PublicKey, +) -> Result { + let mut tx = if let Some(serialized_tx) = serialized_tx { + Tx::deserialize(serialized_tx.as_ref()).map_err(|_| { + Error::Other("Invalid tx deserialization.".to_string()) + })? + } else { + let tx_code_hash = query_wasm_code_hash::<_, IO>( + client, + code_path.unwrap().to_str().unwrap(), + ) + .await + .unwrap(); + let chain_id = tx_args.chain_id.clone().unwrap(); + let mut tx = Tx::new(chain_id, tx_args.expiration); + tx.add_code_from_hash(tx_code_hash); + data_path.map(|data| tx.add_serialized_data(data)); + tx + }; + + prepare_tx::( client, - wallet, - &args.tx, - tx, - TxSigningKey::None, + &tx_args, + &mut tx, + gas_payer.clone(), #[cfg(not(feature = "mainnet"))] false, ) - .await + .await; + Ok(tx) } async fn expect_dry_broadcast< diff --git a/shared/src/types/mod.rs b/shared/src/types/mod.rs index e0b51e5ef1..83e58f0fa8 100644 --- a/shared/src/types/mod.rs +++ b/shared/src/types/mod.rs @@ -6,7 +6,7 @@ pub mod io; pub mod key; pub use namada_core::types::{ - address, chain, dec, eth_abi, eth_bridge_pool, ethereum_events, governance, - hash, internal, keccak, masp, storage, time, token, transaction, uint, + address, chain, dec, eth_abi, eth_bridge_pool, ethereum_events, hash, + internal, keccak, masp, storage, time, token, transaction, uint, validity_predicate, vote_extensions, voting_power, }; diff --git a/shared/src/vm/wasm/run.rs b/shared/src/vm/wasm/run.rs index 9ac4852eed..95cf2afc38 100644 --- a/shared/src/vm/wasm/run.rs +++ b/shared/src/vm/wasm/run.rs @@ -551,7 +551,7 @@ mod tests { wasm::compilation_cache::common::testing::cache(); let (mut tx_cache, _) = wasm::compilation_cache::common::testing::cache(); - let mut outer_tx = Tx::new(TxType::Raw); + let mut outer_tx = Tx::from_type(TxType::Raw); outer_tx.set_code(Code::new(tx_code.clone())); outer_tx.set_data(Data::new(tx_data)); let result = tx( @@ -568,7 +568,7 @@ mod tests { // Allocating `2^24` (16 MiB) should be above the memory limit and // should fail let tx_data = 2_usize.pow(24).try_to_vec().unwrap(); - let mut outer_tx = Tx::new(TxType::Raw); + let mut outer_tx = Tx::from_type(TxType::Raw); outer_tx.set_code(Code::new(tx_code)); outer_tx.set_data(Data::new(tx_data)); let error = tx( @@ -617,18 +617,18 @@ 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 mut tx = Tx::new(storage.chain_id.clone(), None); + tx.add_code(vec![]).add_serialized_data(input); + 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 mut outer_tx = Tx::new(storage.chain_id.clone(), None); + outer_tx.add_code(vec![]).add_data(eval_vp); + 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 +652,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 mut tx = Tx::new(storage.chain_id.clone(), None); + tx.add_code(vec![]).add_data(input); + 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 mut outer_tx = Tx::new(storage.chain_id.clone(), None); + outer_tx.add_code(vec![]).add_data(eval_vp); + // 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`. @@ -711,7 +710,7 @@ mod tests { // Allocating `2^23` (8 MiB) should be below the memory limit and // shouldn't fail let tx_data = 2_usize.pow(23).try_to_vec().unwrap(); - let mut outer_tx = Tx::new(TxType::Raw); + let mut outer_tx = Tx::from_type(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![])); @@ -735,7 +734,7 @@ mod tests { // Allocating `2^24` (16 MiB) should be above the memory limit and // should fail let tx_data = 2_usize.pow(24).try_to_vec().unwrap(); - let mut outer_tx = Tx::new(TxType::Raw); + let mut outer_tx = Tx::from_type(TxType::Raw); outer_tx.header.chain_id = storage.chain_id.clone(); outer_tx.set_data(Data::new(tx_data)); let error = vp( @@ -783,7 +782,7 @@ mod tests { wasm::compilation_cache::common::testing::cache(); let (mut tx_cache, _) = wasm::compilation_cache::common::testing::cache(); - let mut outer_tx = Tx::new(TxType::Raw); + let mut outer_tx = Tx::from_type(TxType::Raw); outer_tx.set_code(Code::new(tx_no_op)); outer_tx.set_data(Data::new(tx_data)); let result = tx( @@ -839,7 +838,7 @@ mod tests { // limit and should fail let len = 2_usize.pow(24); let tx_data: Vec = vec![6_u8; len]; - let mut outer_tx = Tx::new(TxType::Raw); + let mut outer_tx = Tx::from_type(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![])); @@ -911,7 +910,7 @@ mod tests { wasm::compilation_cache::common::testing::cache(); let (mut tx_cache, _) = wasm::compilation_cache::common::testing::cache(); - let mut outer_tx = Tx::new(TxType::Raw); + let mut outer_tx = Tx::from_type(TxType::Raw); outer_tx.set_code(Code::new(tx_read_key)); outer_tx.set_data(Data::new(tx_data)); let error = tx( @@ -959,7 +958,7 @@ mod tests { // Borsh. storage.write(&key, value.try_to_vec().unwrap()).unwrap(); let tx_data = key.try_to_vec().unwrap(); - let mut outer_tx = Tx::new(TxType::Raw); + let mut outer_tx = Tx::from_type(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![])); @@ -1022,18 +1021,18 @@ 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 mut tx = Tx::new(storage.chain_id.clone(), None); + tx.add_code(vec![]).add_serialized_data(input); + 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 mut outer_tx = Tx::new(storage.chain_id.clone(), None); + outer_tx.add_code(vec![]).add_data(eval_vp); + let (vp_cache, _) = wasm::compilation_cache::common::testing::cache(); let passed = vp( &code_hash, @@ -1103,7 +1102,7 @@ mod tests { let key = Key::wasm_code(&code_hash); write_log.write(&key, tx_code).unwrap(); - let mut outer_tx = Tx::new(TxType::Raw); + let mut outer_tx = Tx::from_type(TxType::Raw); outer_tx.set_code(Code::from_hash(code_hash)); outer_tx.set_data(Data::new(tx_data)); @@ -1147,7 +1146,7 @@ mod tests { ) .expect("unexpected error converting wat2wasm").into_owned(); - let outer_tx = Tx::new(TxType::Raw); + let outer_tx = Tx::from_type(TxType::Raw); let tx_index = TxIndex::default(); let mut storage = TestStorage::default(); let addr = storage.address_gen.generate_address("rng seed"); diff --git a/test_fixtures/masp_proofs/0DAF8BDF2318129AC828A7149AC83E76506147445D4DC22D57CBC9869BCDDA80.bin b/test_fixtures/masp_proofs/0DAF8BDF2318129AC828A7149AC83E76506147445D4DC22D57CBC9869BCDDA80.bin new file mode 100644 index 0000000000000000000000000000000000000000..f20cf90f1a573ad377dd0de7a9925cdaee8e6ce2 GIT binary patch literal 9649 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 literal 0 HcmV?d00001 diff --git a/test_fixtures/masp_proofs/1362F1CF9B836CF8B05D8189EA9CB1712CCA85B0E96A3330A63BE7CD9E5ECD22.bin b/test_fixtures/masp_proofs/1362F1CF9B836CF8B05D8189EA9CB1712CCA85B0E96A3330A63BE7CD9E5ECD22.bin new file mode 100644 index 0000000000000000000000000000000000000000..db2cb751aab73b21904e6bf7cdbb2318337809fa GIT binary patch literal 7448 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 literal 0 HcmV?d00001 diff --git a/test_fixtures/masp_proofs/5B99F3D7E0CE75AB1F4B737EC88B269A5436CD72AA758686960F409B04841707.bin b/test_fixtures/masp_proofs/5B99F3D7E0CE75AB1F4B737EC88B269A5436CD72AA758686960F409B04841707.bin new file mode 100644 index 0000000000000000000000000000000000000000..30b0e399a357823df00588f75d8cb3fe88b633f1 GIT binary patch literal 9208 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 N{~tXR6wse9{|2EzDjEO) literal 0 HcmV?d00001 diff --git a/test_fixtures/masp_proofs/889C046FA76727BC97433503BB79BAC90BA1F01653EBCFDCF7CC8AAA1BBEE462.bin b/test_fixtures/masp_proofs/889C046FA76727BC97433503BB79BAC90BA1F01653EBCFDCF7CC8AAA1BBEE462.bin new file mode 100644 index 0000000000000000000000000000000000000000..525e1e63ee265df1384210ff91e0ac248d049253 GIT binary patch literal 25031 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 I+Fs><0Lca^(EtDd literal 0 HcmV?d00001 diff --git a/test_fixtures/masp_proofs/8B29BC2E1A96DF331C7C3A2B227C98D1E5AAAA9988F26B1A47090ACCE693572F.bin b/test_fixtures/masp_proofs/8B29BC2E1A96DF331C7C3A2B227C98D1E5AAAA9988F26B1A47090ACCE693572F.bin new file mode 100644 index 0000000000000000000000000000000000000000..77f5568490073f7a005b95c12fe8efe977a06dc5 GIT binary patch literal 7448 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 literal 0 HcmV?d00001 diff --git a/test_fixtures/masp_proofs/A9FA2730222946FA51E9D587544FDED28D5E7D3C6B52DCF38A5978CEA70D6FD3.bin b/test_fixtures/masp_proofs/A9FA2730222946FA51E9D587544FDED28D5E7D3C6B52DCF38A5978CEA70D6FD3.bin new file mode 100644 index 0000000000000000000000000000000000000000..634d326dcdc00719d8f0f737b56dd64af89d3350 GIT binary patch literal 9649 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 L{pUOWZyWyx8{+`r literal 0 HcmV?d00001 diff --git a/test_fixtures/masp_proofs/AC308C08512AF5DAA364B845D146763B3CE0BACFB7799C6744E50B9E7F43E961.bin b/test_fixtures/masp_proofs/AC308C08512AF5DAA364B845D146763B3CE0BACFB7799C6744E50B9E7F43E961.bin new file mode 100644 index 0000000000000000000000000000000000000000..b67b3c8cd080323210873fd902f72c278f1f4854 GIT binary patch literal 17018 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 JdIku{{{f9vBg+5) literal 0 HcmV?d00001 diff --git a/test_fixtures/masp_proofs/BE57BA4D8FB068F5A933E78DEF2989556FD771D368849D034E22923FD350EEEC.bin b/test_fixtures/masp_proofs/BE57BA4D8FB068F5A933E78DEF2989556FD771D368849D034E22923FD350EEEC.bin new file mode 100644 index 0000000000000000000000000000000000000000..c05883cbab75dd3e0b4adb8f5e9f8896b780939f GIT binary patch literal 19947 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 CT6y*W literal 0 HcmV?d00001 diff --git a/test_fixtures/masp_proofs/E76E54B7526CD2B5423322FB711C0CA6AA6520A2AC8BC34A84358EA137F138D0.bin b/test_fixtures/masp_proofs/E76E54B7526CD2B5423322FB711C0CA6AA6520A2AC8BC34A84358EA137F138D0.bin new file mode 100644 index 0000000000000000000000000000000000000000..4df2e0be9f296c431ccbf45a93b596618360c138 GIT binary patch literal 18792 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%0AZ#;eA|76Rb`B;G|kS4*m#I&fP@uXgr)O_6b!x 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 Ct%%V8 literal 0 HcmV?d00001 diff --git a/test_fixtures/masp_proofs/EE7C912B7E21F07494D58AA6668DC6BBB31619C7E93A1A5A2E64B694DBE1BD6E.bin b/test_fixtures/masp_proofs/EE7C912B7E21F07494D58AA6668DC6BBB31619C7E93A1A5A2E64B694DBE1BD6E.bin new file mode 100644 index 0000000000000000000000000000000000000000..56b269667b85a1d899ad3cf4957cb9665f6c6378 GIT binary patch literal 7448 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 uE?rN|N$s3*$M0VI8o;nOl#z({ PathBuf { let filename = match self { TestWasms::TxMemoryLimit => "tx_memory_limit.wasm", - TestWasms::TxMintTokens => "tx_mint_tokens.wasm", TestWasms::TxNoOp => "tx_no_op.wasm", TestWasms::TxProposalCode => "tx_proposal_code.wasm", TestWasms::TxReadStorageKey => "tx_read_storage_key.wasm", diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 65c0d306f3..674bce9538 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -40,15 +40,15 @@ clap.workspace = true concat-idents.workspace = true derivative.workspace = true hyper = {version = "0.14.20", features = ["full"]} -ibc-relayer-types.workspace = true -ibc-relayer.workspace = true lazy_static.workspace = true num-traits.workspace = true prost.workspace = true regex.workspace = true serde_json.workspace = true +serde.workspace = true sha2.workspace = true tempfile.workspace = true +tendermint-light-client.workspace = true test-log.workspace = true tokio = {workspace = true, features = ["full"]} tracing-subscriber.workspace = true diff --git a/tests/src/e2e/eth_bridge_tests.rs b/tests/src/e2e/eth_bridge_tests.rs index 1d15c5323a..d85b344f45 100644 --- a/tests/src/e2e/eth_bridge_tests.rs +++ b/tests/src/e2e/eth_bridge_tests.rs @@ -144,17 +144,17 @@ async fn test_roundtrip_eth_transfer() -> Result<()> { "add-erc20-transfer", "--address", BERTHA, - "--signer", - BERTHA, + "--signing-keys", + BERTHA_KEY, "--amount", &amount, "--erc20", &dai_addr, "--ethereum-address", RECEIVER, - "--fee-amount", + "--gas-amount", "10", - "--fee-payer", + "--gas-payer", BERTHA, "--gas-amount", "0", @@ -335,17 +335,17 @@ async fn test_bridge_pool_e2e() { "add-erc20-transfer", "--address", BERTHA, - "--signer", - BERTHA, + "--signing-keys", + BERTHA_KEY, "--amount", "100", "--erc20", &wnam_address, "--ethereum-address", RECEIVER, - "--fee-amount", + "--gas-amount", "10", - "--fee-payer", + "--gas-payer", BERTHA, "--gas-amount", "0", diff --git a/tests/src/e2e/eth_bridge_tests/helpers.rs b/tests/src/e2e/eth_bridge_tests/helpers.rs index 09df129e2b..a52273366c 100644 --- a/tests/src/e2e/eth_bridge_tests/helpers.rs +++ b/tests/src/e2e/eth_bridge_tests/helpers.rs @@ -183,7 +183,7 @@ pub fn attempt_wrapped_erc20_transfer( from, "--target", to, - "--signer", + "--signing-keys", signer, "--amount", &amount, diff --git a/tests/src/e2e/helpers.rs b/tests/src/e2e/helpers.rs index 1fde997ef6..e2d887b5a2 100644 --- a/tests/src/e2e/helpers.rs +++ b/tests/src/e2e/helpers.rs @@ -458,3 +458,9 @@ pub fn wait_for_wasm_pre_compile(ledger: &mut NamadaCmd) -> Result<()> { ledger.exp_string("Finished compiling all")?; Ok(()) } + +/// Convert epoch `min_duration` in seconds to `epochs_per_year` genesis +/// parameter. +pub fn epochs_per_year_from_min_duration(min_duration: u64) -> u64 { + 60 * 60 * 24 * 365 / min_duration +} diff --git a/tests/src/e2e/ibc_tests.rs b/tests/src/e2e/ibc_tests.rs index a7f89d9a9f..bbc959908f 100644 --- a/tests/src/e2e/ibc_tests.rs +++ b/tests/src/e2e/ibc_tests.rs @@ -12,56 +12,43 @@ use core::convert::TryFrom; use core::str::FromStr; use core::time::Duration; +use std::collections::HashMap; use color_eyre::eyre::Result; use eyre::eyre; -use ibc_relayer::client_state::AnyClientState; -use ibc_relayer::config::types::{MaxMsgNum, MaxTxSize, Memo}; -use ibc_relayer::config::{AddressType, ChainConfig, GasPrice, PacketFilter}; -use ibc_relayer::event::ibc_event_try_from_abci_event; -use ibc_relayer::keyring::Store; -use ibc_relayer::light_client::tendermint::LightClient as TmLightClient; -use ibc_relayer::light_client::{LightClient, Verified}; -use ibc_relayer_types::clients::ics07_tendermint::client_state::{ +use namada::ibc::applications::transfer::VERSION as ICS20_VERSION; +use namada::ibc::clients::ics07_tendermint::client_state::{ AllowUpdate, ClientState as TmClientState, }; -use ibc_relayer_types::clients::ics07_tendermint::consensus_state::ConsensusState as TmConsensusState; -use ibc_relayer_types::core::ics02_client::msgs::create_client::MsgCreateClient; -use ibc_relayer_types::core::ics02_client::msgs::update_client::MsgUpdateClient; -use ibc_relayer_types::core::ics02_client::trust_threshold::TrustThreshold; -use ibc_relayer_types::core::ics03_connection::connection::Counterparty as ConnCounterparty; -use ibc_relayer_types::core::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; -use ibc_relayer_types::core::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; -use ibc_relayer_types::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; -use ibc_relayer_types::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; -use ibc_relayer_types::core::ics03_connection::version::Version as ConnVersion; -use ibc_relayer_types::core::ics04_channel::channel::{ - ChannelEnd, Counterparty as ChanCounterparty, Order as ChanOrder, - State as ChanState, +use namada::ibc::clients::ics07_tendermint::consensus_state::ConsensusState as TmConsensusState; +use namada::ibc::clients::ics07_tendermint::header::Header as IbcTmHeader; +use namada::ibc::clients::ics07_tendermint::trust_threshold::TrustThreshold; +use namada::ibc::core::ics02_client::client_state::ClientState; +use namada::ibc::core::ics02_client::msgs::create_client::MsgCreateClient; +use namada::ibc::core::ics02_client::msgs::update_client::MsgUpdateClient; +use namada::ibc::core::ics03_connection::connection::Counterparty as ConnCounterparty; +use namada::ibc::core::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; +use namada::ibc::core::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; +use namada::ibc::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; +use namada::ibc::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; +use namada::ibc::core::ics03_connection::version::Version as ConnVersion; +use namada::ibc::core::ics04_channel::channel::Order as ChanOrder; +use namada::ibc::core::ics04_channel::msgs::{ + MsgAcknowledgement, MsgChannelOpenAck, MsgChannelOpenConfirm, + MsgChannelOpenInit, MsgChannelOpenTry, MsgRecvPacket, MsgTimeout, }; -use ibc_relayer_types::core::ics04_channel::msgs::acknowledgement::MsgAcknowledgement; -use ibc_relayer_types::core::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; -use ibc_relayer_types::core::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; -use ibc_relayer_types::core::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; -use ibc_relayer_types::core::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; -use ibc_relayer_types::core::ics04_channel::msgs::recv_packet::MsgRecvPacket; -use ibc_relayer_types::core::ics04_channel::msgs::timeout::MsgTimeout; -use ibc_relayer_types::core::ics04_channel::packet::Packet; -use ibc_relayer_types::core::ics04_channel::version::Version as ChanVersion; -use ibc_relayer_types::core::ics23_commitment::commitment::{ +use namada::ibc::core::ics04_channel::packet::Packet; +use namada::ibc::core::ics04_channel::timeout::TimeoutHeight; +use namada::ibc::core::ics04_channel::Version as ChanVersion; +use namada::ibc::core::ics23_commitment::commitment::{ CommitmentPrefix, CommitmentProofBytes, }; -use ibc_relayer_types::core::ics23_commitment::merkle::convert_tm_to_ics_merkle_proof; -use ibc_relayer_types::core::ics24_host::identifier::{ - ChainId, ClientId, ConnectionId, PortChannelId, PortId, +use namada::ibc::core::ics23_commitment::merkle::MerkleProof; +use namada::ibc::core::ics24_host::identifier::{ + ChainId, ChannelId, ClientId, ConnectionId, PortId, }; -use ibc_relayer_types::events::IbcEvent; -use ibc_relayer_types::proofs::{ConsensusProof, Proofs}; -use ibc_relayer_types::signer::Signer; -use ibc_relayer_types::tx_msg::Msg; -use ibc_relayer_types::Height; -use namada::ibc::core::ics24_host::identifier::PortChannelId as IbcPortChannelId; -use namada::ibc::Height as IbcHeight; +use namada::ibc::core::Msg; +use namada::ibc::{Height, Signer}; use namada::ibc_proto::google::protobuf::Any; use namada::ledger::events::EventType; use namada::ledger::ibc::storage::*; @@ -70,6 +57,8 @@ use namada::ledger::pos::{self, PosParams}; use namada::ledger::queries::RPC; use namada::ledger::storage::ics23_specs::ibc_proof_specs; use namada::ledger::storage::traits::Sha256Hasher; +use namada::tendermint::abci::Event as AbciEvent; +use namada::tendermint::block::Height as TmHeight; use namada::types::address::{Address, InternalAddress}; use namada::types::key::PublicKey; use namada::types::storage::{BlockHeight, Key}; @@ -82,12 +71,13 @@ use namada_apps::config::ethereum_bridge; use namada_apps::config::genesis::genesis_config::GenesisConfig; use namada_apps::facade::tendermint::block::Header as TmHeader; use namada_apps::facade::tendermint::merkle::proof::Proof as TmProof; -use namada_apps::facade::tendermint::trust_threshold::TrustThresholdFraction; use namada_apps::facade::tendermint_config::net::Address as TendermintAddress; use namada_apps::facade::tendermint_rpc::{Client, HttpClient, Url}; use prost::Message; use setup::constants::*; +use tendermint_light_client::components::io::{Io, ProdIo as TmLightClientIo}; +use super::helpers::wait_for_wasm_pre_compile; use super::setup::set_ethereum_bridge_mode; use crate::e2e::helpers::{find_address, get_actor_rpc, get_validator_pk}; use crate::e2e::setup::{self, sleep, Bin, NamadaCmd, Test, Who}; @@ -132,6 +122,9 @@ fn run_ledger_ibc() -> Result<()> { ledger_a.exp_string("This node is a validator")?; ledger_b.exp_string("This node is a validator")?; + wait_for_wasm_pre_compile(&mut ledger_a)?; + wait_for_wasm_pre_compile(&mut ledger_b)?; + // Wait for a first block ledger_a.exp_string("Committed block hash")?; ledger_b.exp_string("Committed block hash")?; @@ -146,14 +139,15 @@ fn run_ledger_ibc() -> Result<()> { let (conn_id_a, conn_id_b) = connection_handshake(&test_a, &test_b, &client_id_a, &client_id_b)?; - let (port_channel_id_a, port_channel_id_b) = channel_handshake( - &test_a, - &test_b, - &client_id_a, - &client_id_b, - &conn_id_a, - &conn_id_b, - )?; + let ((port_id_a, channel_id_a), (port_id_b, channel_id_b)) = + channel_handshake( + &test_a, + &test_b, + &client_id_a, + &client_id_b, + &conn_id_a, + &conn_id_b, + )?; // Transfer 100000 from the normal account on Chain A to Chain B transfer_token( @@ -161,13 +155,14 @@ fn run_ledger_ibc() -> Result<()> { &test_b, &client_id_a, &client_id_b, - &port_channel_id_a, + &port_id_a, + &channel_id_a, )?; - check_balances(&port_channel_id_b, &test_a, &test_b)?; + check_balances(&port_id_b, &channel_id_b, &test_a, &test_b)?; // Transfer 50000 received over IBC on Chain B - transfer_received_token(&port_channel_id_b, &test_b)?; - check_balances_after_non_ibc(&port_channel_id_b, &test_b)?; + transfer_received_token(&port_id_b, &channel_id_b, &test_b)?; + check_balances_after_non_ibc(&port_id_b, &channel_id_b, &test_b)?; // Transfer 50000 back from the origin-specific account on Chain B to Chain // A @@ -176,14 +171,21 @@ fn run_ledger_ibc() -> Result<()> { &test_b, &client_id_a, &client_id_b, - &port_channel_id_b, + &port_id_b, + &channel_id_b, )?; - check_balances_after_back(&port_channel_id_b, &test_a, &test_b)?; + check_balances_after_back(&port_id_b, &channel_id_b, &test_a, &test_b)?; // Transfer a token and it will time out and refund - transfer_timeout(&test_a, &test_b, &client_id_a, &port_channel_id_a)?; + transfer_timeout( + &test_a, + &test_b, + &client_id_a, + &port_id_a, + &channel_id_a, + )?; // The balance should not be changed - check_balances_after_back(&port_channel_id_b, &test_a, &test_b)?; + check_balances_after_back(&port_id_b, &channel_id_b, &test_a, &test_b)?; // Skip tests for closing a channel and timeout_on_close since the transfer // channel cannot be closed @@ -214,9 +216,9 @@ fn create_client(test_a: &Test, test_b: &Test) -> Result<(ClientId, ClientId)> { let message = MsgCreateClient { client_state: client_state.into(), consensus_state: make_consensus_state(test_b, height)?.into(), - signer: Signer::from_str("test_a").expect("invalid signer"), + signer: signer(), }; - let height_a = submit_ibc_tx(test_a, message, ALBERT)?; + let height_a = submit_ibc_tx(test_a, message, ALBERT, ALBERT_KEY, false)?; let height = query_height(test_a)?; let client_state = make_client_state(test_a, height); @@ -224,23 +226,16 @@ fn create_client(test_a: &Test, test_b: &Test) -> Result<(ClientId, ClientId)> { let message = MsgCreateClient { client_state: client_state.into(), consensus_state: make_consensus_state(test_a, height)?.into(), - signer: Signer::from_str("test_b").expect("invalid signer"), + signer: signer(), }; - let height_b = submit_ibc_tx(test_b, message, ALBERT)?; + let height_b = submit_ibc_tx(test_b, message, ALBERT, ALBERT_KEY, false)?; - // convert the client IDs from `ibc_relayer_type` to `ibc` - let client_id_a = match get_event(test_a, height_a)? { - Some(IbcEvent::CreateClient(event)) => { - ClientId::from_str(event.client_id().as_str()).unwrap() - } - _ => return Err(eyre!("Transaction failed")), - }; - let client_id_b = match get_event(test_b, height_b)? { - Some(IbcEvent::CreateClient(event)) => { - ClientId::from_str(event.client_id().as_str()).unwrap() - } - _ => return Err(eyre!("Transaction failed")), - }; + let events = get_events(test_a, height_a)?; + let client_id_a = get_client_id_from_events(&events) + .ok_or(eyre!("Transaction failed"))?; + let events = get_events(test_b, height_b)?; + let client_id_b = get_client_id_from_events(&events) + .ok_or(eyre!("Transaction failed"))?; // `client_id_a` represents the ID of the B's client on Chain A Ok((client_id_a, client_id_b)) @@ -303,7 +298,7 @@ fn update_client_with_height( target_height: Height, ) -> Result<()> { // check the current(stale) state on the target chain - let key = client_state_key(&target_client_id.as_str().parse().unwrap()); + let key = client_state_key(target_client_id); let (value, _) = query_value_with_proof(target_test, &key, None)?; let cs = match value { Some(v) => Any::decode(&v[..]) @@ -325,7 +320,6 @@ fn update_client_with_height( target_client_id, trusted_height, target_height, - client_state, ) } @@ -335,36 +329,35 @@ fn update_client( client_id: &ClientId, trusted_height: Height, target_height: Height, - client_state: TmClientState, ) -> Result<()> { - let config = dummy_chain_config(src_test); - let pk = get_validator_pk(src_test, &Who::Validator(0)).unwrap(); - let peer_id = id_from_pk(&PublicKey::try_from_pk(&pk).unwrap()); - let mut light_client = - TmLightClient::from_config(&config, peer_id).unwrap(); - let Verified { target, supporting } = light_client - .header_and_minimal_set( - trusted_height, - target_height, - &AnyClientState::Tendermint(client_state), - ) - .map_err(|e| eyre!("Building the header failed: {}", e))?; - - for header in supporting { - let message = MsgUpdateClient { - header: header.into(), - client_id: client_id.clone(), - signer: Signer::from_str("test").expect("invalid signer"), - }; - submit_ibc_tx(target_test, message, ALBERT)?; - } + let io = make_light_client_io(src_test); + + let height = TmHeight::try_from(trusted_height.revision_height()) + .expect("invalid height"); + let trusted_block = io + .fetch_light_block(height.into()) + .expect("the light client couldn't get a light block"); + + let height = TmHeight::try_from(target_height.revision_height()) + .expect("invalid height"); + let target_block = io + .fetch_light_block(height.into()) + .expect("the light client couldn't get a light block"); + + let header = IbcTmHeader { + signed_header: target_block.signed_header, + validator_set: target_block.validators, + trusted_height: Height::new(0, u64::from(trusted_block.height())) + .expect("invalid height"), + trusted_next_validator_set: trusted_block.next_validators, + }; let message = MsgUpdateClient { - header: target.into(), + header: header.into(), client_id: client_id.clone(), - signer: Signer::from_str("test").expect("invalid signer"), + signer: signer(), }; - submit_ibc_tx(target_test, message, ALBERT)?; + submit_ibc_tx(target_test, message, ALBERT, ALBERT_KEY, false)?; check_ibc_update_query( target_test, @@ -374,40 +367,16 @@ fn update_client( Ok(()) } -fn dummy_chain_config(test: &Test) -> ChainConfig { +fn make_light_client_io(test: &Test) -> TmLightClientIo { let addr = format!("http://{}", get_actor_rpc(test, &Who::Validator(0))); let rpc_addr = Url::from_str(&addr).unwrap(); - // use only id and rpc_addr - ChainConfig { - id: ChainId::new(test.net.chain_id.as_str().to_string(), 0), - r#type: ibc_relayer::chain::ChainType::CosmosSdk, - rpc_addr: rpc_addr.clone(), - websocket_addr: rpc_addr.clone(), - grpc_addr: rpc_addr, - rpc_timeout: Duration::new(10, 0), - account_prefix: "dummy".to_string(), - key_name: "dummy".to_string(), - key_store_type: Store::default(), - store_prefix: "dummy".to_string(), - default_gas: None, - max_gas: None, - gas_adjustment: None, - gas_multiplier: None, - fee_granter: None, - max_msg_num: MaxMsgNum::default(), - max_tx_size: MaxTxSize::default(), - clock_drift: Duration::new(5, 0), - max_block_time: Duration::new(5, 0), - trusting_period: None, - memo_prefix: Memo::default(), - proof_specs: Some(ibc_proof_specs::().into()), - sequential_batch_tx: true, - trust_threshold: TrustThresholdFraction::ONE_THIRD, - gas_price: GasPrice::new(0.0, "dummy".to_string()), - packet_filter: PacketFilter::default(), - address_type: AddressType::Cosmos, - extension_options: Vec::new(), - } + let rpc_client = HttpClient::new(rpc_addr).unwrap(); + let rpc_timeout = Duration::new(10, 0); + + let pk = get_validator_pk(test, &Who::Validator(0)).unwrap(); + let peer_id = id_from_pk(&PublicKey::try_from_pk(&pk).unwrap()); + + TmLightClientIo::new(peer_id, rpc_client, Some(rpc_timeout)) } fn connection_handshake( @@ -417,117 +386,100 @@ fn connection_handshake( client_id_b: &ClientId, ) -> Result<(ConnectionId, ConnectionId)> { let msg = MsgConnectionOpenInit { - client_id: client_id_a.clone(), + client_id_on_a: client_id_a.clone(), counterparty: ConnCounterparty::new( client_id_b.clone(), None, commitment_prefix(), ), version: Some(ConnVersion::default()), - delay_period: Duration::new(1, 0), - signer: Signer::from_str("test_a").expect("invalid signer"), + delay_period: Duration::new(0, 0), + signer: signer(), }; // OpenInitConnection on Chain A - let height = submit_ibc_tx(test_a, msg, ALBERT)?; - let conn_id_a = match get_event(test_a, height)? { - Some(IbcEvent::OpenInitConnection(event)) => event - .connection_id() - .cloned() - .ok_or(eyre!("No connection ID is set"))?, - _ => return Err(eyre!("Transaction failed")), - }; + let height = submit_ibc_tx(test_a, msg, ALBERT, ALBERT_KEY, false)?; + let events = get_events(test_a, height)?; + let conn_id_a = get_connection_id_from_events(&events) + .ok_or(eyre!("No connection ID is set"))?; // get the proofs from Chain A let height_a = query_height(test_a)?; - let (client_state, proofs) = - get_connection_proofs(test_a, client_id_a, &conn_id_a, height_a)?; + let conn_proof = get_connection_proof(test_a, &conn_id_a, height_a)?; + let (client_state, client_state_proof, consensus_proof) = + get_client_states(test_a, client_id_a, height_a)?; let counterparty = ConnCounterparty::new( client_id_a.clone(), Some(conn_id_a.clone()), commitment_prefix(), ); - let msg = MsgConnectionOpenTry { - previous_connection_id: None, - client_id: client_id_b.clone(), - client_state: Some(client_state.into()), + let msg = make_msg_conn_open_try( + client_id_b.clone(), + client_state, counterparty, - counterparty_versions: vec![ConnVersion::default()], - proofs, - delay_period: Duration::new(1, 0), - signer: Signer::from_str("test_b").expect("invalid signer"), - }; + conn_proof, + client_state_proof, + consensus_proof, + height_a, + ); // Update the client state of Chain A on Chain B update_client_with_height(test_a, test_b, client_id_b, height_a)?; // OpenTryConnection on Chain B - let height = submit_ibc_tx(test_b, msg, ALBERT)?; - let conn_id_b = match get_event(test_b, height)? { - Some(IbcEvent::OpenTryConnection(event)) => event - .connection_id() - .cloned() - .ok_or(eyre!("No connection ID is set"))?, - _ => return Err(eyre!("Transaction failed")), - }; + let height = submit_ibc_tx(test_b, msg, ALBERT, ALBERT_KEY, false)?; + let events = get_events(test_b, height)?; + let conn_id_b = get_connection_id_from_events(&events) + .ok_or(eyre!("No connection ID is set"))?; // get the A's proofs on Chain B let height_b = query_height(test_b)?; - let (client_state, proofs) = - get_connection_proofs(test_b, client_id_b, &conn_id_b, height_b)?; + let conn_proof = get_connection_proof(test_b, &conn_id_b, height_b)?; + let (client_state, client_state_proof, consensus_proof) = + get_client_states(test_b, client_id_b, height_b)?; + let consensus_height_of_a_on_b = client_state.latest_height(); let msg = MsgConnectionOpenAck { - connection_id: conn_id_a.clone(), - counterparty_connection_id: conn_id_b.clone(), - client_state: Some(client_state.into()), - proofs, + conn_id_on_a: conn_id_a.clone(), + conn_id_on_b: conn_id_b.clone(), + client_state_of_a_on_b: client_state.into(), + proof_conn_end_on_b: conn_proof, + proof_client_state_of_a_on_b: client_state_proof, + proof_consensus_state_of_a_on_b: consensus_proof, + proofs_height_on_b: height_b, + consensus_height_of_a_on_b, version: ConnVersion::default(), - signer: Signer::from_str("test_a").expect("invalid signer"), + signer: signer(), }; // Update the client state of Chain B on Chain A update_client_with_height(test_b, test_a, client_id_a, height_b)?; // OpenAckConnection on Chain A - submit_ibc_tx(test_a, msg, ALBERT)?; + submit_ibc_tx(test_a, msg, ALBERT, ALBERT_KEY, false)?; // get the proofs on Chain A let height_a = query_height(test_a)?; - let (_, proofs) = - get_connection_proofs(test_a, client_id_a, &conn_id_a, height_a)?; + let proof = get_connection_proof(test_a, &conn_id_a, height_a)?; let msg = MsgConnectionOpenConfirm { - connection_id: conn_id_b.clone(), - proofs, - signer: Signer::from_str("test_b").expect("invalid signer"), + conn_id_on_b: conn_id_b.clone(), + proof_conn_end_on_a: proof, + proof_height_on_a: height_a, + signer: signer(), }; // Update the client state of Chain A on Chain B update_client_with_height(test_a, test_b, client_id_b, height_a)?; // OpenConfirmConnection on Chain B - submit_ibc_tx(test_b, msg, ALBERT)?; + submit_ibc_tx(test_b, msg, ALBERT, ALBERT_KEY, false)?; Ok((conn_id_a, conn_id_b)) } // get the proofs on the target height -fn get_connection_proofs( +fn get_connection_proof( test: &Test, - client_id: &ClientId, conn_id: &ConnectionId, target_height: Height, -) -> Result<(TmClientState, Proofs)> { +) -> Result { // we need proofs at the height of the previous block let query_height = target_height.decrement().unwrap(); - let key = connection_key(&conn_id.as_str().parse().unwrap()); + let key = connection_key(conn_id); let (_, tm_proof) = query_value_with_proof(test, &key, Some(query_height))?; - let connection_proof = convert_proof(tm_proof)?; - - let (client_state, client_state_proof, consensus_proof) = - get_client_states(test, client_id, query_height)?; - - let proofs = Proofs::new( - connection_proof, - Some(client_state_proof), - Some(consensus_proof), - None, - target_height, - ) - .map_err(|e| eyre!("Creating proofs failed: error {}", e))?; - - Ok((client_state, proofs)) + convert_proof(tm_proof) } fn channel_handshake( @@ -537,131 +489,99 @@ fn channel_handshake( client_id_b: &ClientId, conn_id_a: &ConnectionId, conn_id_b: &ConnectionId, -) -> Result<(PortChannelId, PortChannelId)> { +) -> Result<((PortId, ChannelId), (PortId, ChannelId))> { // OpenInitChannel on Chain A let port_id = PortId::transfer(); - let counterparty = ChanCounterparty::new(port_id.clone(), None); - let channel = ChannelEnd::new( - ChanState::Init, - ChanOrder::Unordered, - counterparty, - vec![conn_id_a.clone()], - ChanVersion::ics20(), - ); + let connection_hops_on_a = vec![conn_id_a.clone()]; + let channel_version = ChanVersion::new(ICS20_VERSION.to_string()); let msg = MsgChannelOpenInit { - port_id: port_id.clone(), - channel, - signer: Signer::from_str("test_a").expect("invalid signer"), + port_id_on_a: port_id.clone(), + connection_hops_on_a, + port_id_on_b: port_id.clone(), + ordering: ChanOrder::Unordered, + signer: signer(), + version_proposal: channel_version.clone(), }; - let height = submit_ibc_tx(test_a, msg, ALBERT)?; - let channel_id_a = - match get_event(test_a, height)? { - Some(IbcEvent::OpenInitChannel(event)) => event - .channel_id() - .cloned() - .ok_or(eyre!("No channel ID is set"))?, - _ => return Err(eyre!("Transaction failed")), - }; - let port_channel_id_a = - PortChannelId::new(channel_id_a.clone(), port_id.clone()); + let height = submit_ibc_tx(test_a, msg, ALBERT, ALBERT_KEY, false)?; + let events = get_events(test_a, height)?; + let channel_id_a = get_channel_id_from_events(&events) + .ok_or(eyre!("Transaction failed"))?; // get the proofs from Chain A let height_a = query_height(test_a)?; - let proofs = - get_channel_proofs(test_a, client_id_a, &port_channel_id_a, height_a)?; - let counterparty = - ChanCounterparty::new(port_id.clone(), Some(channel_id_a.clone())); - let channel = ChannelEnd::new( - ChanState::TryOpen, - ChanOrder::Unordered, - counterparty, - vec![conn_id_b.clone()], - ChanVersion::ics20(), - ); + let proof_chan_end_on_a = + get_channel_proof(test_a, &port_id, &channel_id_a, height_a)?; + let connection_hops_on_b = vec![conn_id_b.clone()]; + #[allow(deprecated)] let msg = MsgChannelOpenTry { - port_id: port_id.clone(), - previous_channel_id: None, - channel, - counterparty_version: ChanVersion::ics20(), - proofs, - signer: Signer::from_str("test_b").expect("invalid signer"), + port_id_on_b: port_id.clone(), + connection_hops_on_b, + port_id_on_a: port_id.clone(), + chan_id_on_a: channel_id_a.clone(), + version_supported_on_a: channel_version.clone(), + proof_chan_end_on_a, + proof_height_on_a: height_a, + ordering: ChanOrder::Unordered, + signer: signer(), + version_proposal: channel_version.clone(), }; + // Update the client state of Chain A on Chain B update_client_with_height(test_a, test_b, client_id_b, height_a)?; // OpenTryChannel on Chain B - let height = submit_ibc_tx(test_b, msg, ALBERT)?; - let channel_id_b = match get_event(test_b, height)? { - Some(IbcEvent::OpenTryChannel(event)) => event - .channel_id() - .cloned() - .ok_or(eyre!("No channel ID is set"))?, - _ => return Err(eyre!("Transaction failed")), - }; - let port_channel_id_b = - PortChannelId::new(channel_id_b.clone(), port_id.clone()); + let height = submit_ibc_tx(test_b, msg, ALBERT, ALBERT_KEY, false)?; + let events = get_events(test_b, height)?; + let channel_id_b = get_channel_id_from_events(&events) + .ok_or(eyre!("Transaction failed"))?; // get the A's proofs on Chain B let height_b = query_height(test_b)?; - let proofs = - get_channel_proofs(test_b, client_id_b, &port_channel_id_b, height_b)?; + let proof_chan_end_on_b = + get_channel_proof(test_b, &port_id, &channel_id_b, height_b)?; let msg = MsgChannelOpenAck { - port_id: port_id.clone(), - channel_id: channel_id_a, - counterparty_channel_id: channel_id_b.clone(), - counterparty_version: ChanVersion::ics20(), - proofs, - signer: Signer::from_str("test_a").expect("invalid signer"), + port_id_on_a: port_id.clone(), + chan_id_on_a: channel_id_a.clone(), + chan_id_on_b: channel_id_b.clone(), + version_on_b: channel_version, + proof_chan_end_on_b, + proof_height_on_b: height_b, + signer: signer(), }; // Update the client state of Chain B on Chain A update_client_with_height(test_b, test_a, client_id_a, height_b)?; // OpenAckChannel on Chain A - submit_ibc_tx(test_a, msg, ALBERT)?; + submit_ibc_tx(test_a, msg, ALBERT, ALBERT_KEY, false)?; // get the proofs on Chain A let height_a = query_height(test_a)?; - let proofs = - get_channel_proofs(test_a, client_id_a, &port_channel_id_a, height_a)?; + let proof_chan_end_on_a = + get_channel_proof(test_a, &port_id, &channel_id_a, height_a)?; let msg = MsgChannelOpenConfirm { - port_id, - channel_id: channel_id_b, - proofs, - signer: Signer::from_str("test_b").expect("invalid signer"), + port_id_on_b: port_id.clone(), + chan_id_on_b: channel_id_b.clone(), + proof_chan_end_on_a, + proof_height_on_a: height_a, + signer: signer(), }; // Update the client state of Chain A on Chain B update_client_with_height(test_a, test_b, client_id_b, height_a)?; // OpenConfirmChannel on Chain B - submit_ibc_tx(test_b, msg, ALBERT)?; + submit_ibc_tx(test_b, msg, ALBERT, ALBERT_KEY, false)?; - Ok((port_channel_id_a, port_channel_id_b)) + Ok(((port_id.clone(), channel_id_a), (port_id, channel_id_b))) } -fn get_channel_proofs( +fn get_channel_proof( test: &Test, - client_id: &ClientId, - port_channel_id: &PortChannelId, + port_id: &PortId, + channel_id: &ChannelId, target_height: Height, -) -> Result { +) -> Result { // we need proofs at the height of the previous block let query_height = target_height.decrement().unwrap(); - let port_channel_id = IbcPortChannelId::new( - port_channel_id.channel_id.as_str().parse().unwrap(), - port_channel_id.port_id.as_str().parse().unwrap(), - ); - let key = channel_key(&port_channel_id); + let key = channel_key(port_id, channel_id); let (_, tm_proof) = query_value_with_proof(test, &key, Some(query_height))?; - let proof = convert_proof(tm_proof)?; - - let (_, client_state_proof, consensus_proof) = - get_client_states(test, client_id, query_height)?; - - Proofs::new( - proof, - Some(client_state_proof), - Some(consensus_proof), - None, - target_height, - ) - .map_err(|e| eyre!("Creating proofs failed: error {}", e)) + convert_proof(tm_proof) } // get the client state, the proof of the client state, and the proof of the @@ -670,10 +590,12 @@ fn get_client_states( test: &Test, client_id: &ClientId, target_height: Height, // should have been already decremented -) -> Result<(TmClientState, CommitmentProofBytes, ConsensusProof)> { - let key = client_state_key(&client_id.as_str().parse().unwrap()); +) -> Result<(TmClientState, CommitmentProofBytes, CommitmentProofBytes)> { + // we need proofs at the height of the previous block + let query_height = target_height.decrement().unwrap(); + let key = client_state_key(client_id); let (value, tm_proof) = - query_value_with_proof(test, &key, Some(target_height))?; + query_value_with_proof(test, &key, Some(query_height))?; let cs = match value { Some(v) => Any::decode(&v[..]) .map_err(|e| eyre!("Decoding the client state failed: {}", e))?, @@ -689,14 +611,10 @@ fn get_client_states( let client_state_proof = convert_proof(tm_proof)?; let height = client_state.latest_height(); - let ibc_height = IbcHeight::new(0, height.revision_height()).unwrap(); - let key = - consensus_state_key(&client_id.as_str().parse().unwrap(), ibc_height); - let (_, tm_proof) = - query_value_with_proof(test, &key, Some(target_height))?; - let proof = convert_proof(tm_proof)?; - let consensus_proof = ConsensusProof::new(proof, height) - .map_err(|e| eyre!("Creating ConsensusProof failed: error {}", e))?; + let ibc_height = Height::new(0, height.revision_height()).unwrap(); + let key = consensus_state_key(client_id, ibc_height); + let (_, tm_proof) = query_value_with_proof(test, &key, Some(query_height))?; + let consensus_proof = convert_proof(tm_proof)?; Ok((client_state, client_state_proof, consensus_proof)) } @@ -706,7 +624,8 @@ fn transfer_token( test_b: &Test, client_id_a: &ClientId, client_id_b: &ClientId, - port_channel_id_a: &PortChannelId, + port_id_a: &PortId, + channel_id_a: &ChannelId, ) -> Result<()> { // Send a token from Chain A let receiver = find_address(test_b, BERTHA)?; @@ -716,32 +635,35 @@ fn transfer_token( &receiver, NAM, &Amount::native_whole(100000), - port_channel_id_a, + ALBERT_KEY, + port_id_a, + channel_id_a, None, + false, )?; - let packet = match get_event(test_a, height)? { - Some(IbcEvent::SendPacket(event)) => event.packet, - _ => return Err(eyre!("Transaction failed")), - }; + let events = get_events(test_a, height)?; + let packet = + get_packet_from_events(&events).ok_or(eyre!("Transaction failed"))?; check_ibc_packet_query(test_a, &"send_packet".parse().unwrap(), &packet)?; let height_a = query_height(test_a)?; - let proofs = get_commitment_proof(test_a, &packet, height_a)?; + let proof_commitment_on_a = + get_commitment_proof(test_a, &packet, height_a)?; let msg = MsgRecvPacket { packet, - proofs, - signer: Signer::from_str("test_b").expect("invalid signer"), + proof_commitment_on_a, + proof_height_on_a: height_a, + signer: signer(), }; // Update the client state of Chain A on Chain B update_client_with_height(test_a, test_b, client_id_b, height_a)?; // Receive the token on Chain B - let height = submit_ibc_tx(test_b, msg, ALBERT)?; - let (acknowledgement, packet) = match get_event(test_b, height)? { - Some(IbcEvent::WriteAcknowledgement(event)) => { - (event.ack, event.packet) - } - _ => return Err(eyre!("Transaction failed")), - }; + let height = submit_ibc_tx(test_b, msg, ALBERT, ALBERT_KEY, false)?; + let events = get_events(test_b, height)?; + let packet = + get_packet_from_events(&events).ok_or(eyre!("Transaction failed"))?; + let ack = + get_ack_from_events(&events).ok_or(eyre!("Transaction failed"))?; check_ibc_packet_query( test_b, &"write_acknowledgement".parse().unwrap(), @@ -750,31 +672,30 @@ fn transfer_token( // get the proof on Chain B let height_b = query_height(test_b)?; - let proofs = get_ack_proof(test_b, &packet, height_b)?; + let proof_acked_on_b = get_ack_proof(test_b, &packet, height_b)?; let msg = MsgAcknowledgement { packet, - acknowledgement: acknowledgement.into(), - proofs, - signer: Signer::from_str("test_a").expect("invalid signer"), + acknowledgement: ack.try_into().expect("invalid ack"), + proof_acked_on_b, + proof_height_on_b: height_b, + signer: signer(), }; // Update the client state of Chain B on Chain A update_client_with_height(test_b, test_a, client_id_a, height_b)?; // Acknowledge on Chain A - submit_ibc_tx(test_a, msg, ALBERT)?; + submit_ibc_tx(test_a, msg, ALBERT, ALBERT_KEY, false)?; Ok(()) } fn transfer_received_token( - port_channel_id: &PortChannelId, + port_id: &PortId, + channel_id: &ChannelId, test: &Test, ) -> Result<()> { - let xan = find_address(test, NAM)?; + let nam = find_address(test, NAM)?; // token received via the port and channel - let denom = format!( - "{}/{}/{}", - port_channel_id.port_id, port_channel_id.channel_id, xan - ); + let denom = format!("{port_id}/{channel_id}/{nam}"); let ibc_token = ibc_token(denom).to_string(); let rpc = get_actor_rpc(test, &Who::Validator(0)); @@ -811,16 +732,14 @@ fn transfer_back( test_b: &Test, client_id_a: &ClientId, client_id_b: &ClientId, - port_channel_id_b: &PortChannelId, + port_id_b: &PortId, + channel_id_b: &ChannelId, ) -> Result<()> { - let xan = find_address(test_b, NAM)?.to_string(); + let nam = find_address(test_b, NAM)?.to_string(); let receiver = find_address(test_a, ALBERT)?; // Chain A was the source for the sent token - let denom_raw = format!( - "{}/{}/{}", - port_channel_id_b.port_id, port_channel_id_b.channel_id, xan - ); + let denom_raw = format!("{}/{}/{}", port_id_b, channel_id_b, nam); let ibc_token = ibc_token(denom_raw).to_string(); // Send a token from Chain B let height = transfer( @@ -829,45 +748,48 @@ fn transfer_back( &receiver, ibc_token, &Amount::native_whole(50000), - port_channel_id_b, + BERTHA_KEY, + port_id_b, + channel_id_b, None, + false, )?; - let packet = match get_event(test_b, height)? { - Some(IbcEvent::SendPacket(event)) => event.packet, - _ => return Err(eyre!("Transaction failed")), - }; + let events = get_events(test_b, height)?; + let packet = + get_packet_from_events(&events).ok_or(eyre!("Transaction failed"))?; let height_b = query_height(test_b)?; - let proofs = get_commitment_proof(test_b, &packet, height_b)?; + let proof = get_commitment_proof(test_b, &packet, height_b)?; let msg = MsgRecvPacket { packet, - proofs, - signer: Signer::from_str("test_a").expect("invalid signer"), + proof_commitment_on_a: proof, + proof_height_on_a: height_b, + signer: signer(), }; // Update the client state of Chain B on Chain A update_client_with_height(test_b, test_a, client_id_a, height_b)?; // Receive the token on Chain A - let height = submit_ibc_tx(test_a, msg, ALBERT)?; - let (acknowledgement, packet) = match get_event(test_a, height)? { - Some(IbcEvent::WriteAcknowledgement(event)) => { - (event.ack, event.packet) - } - _ => return Err(eyre!("Transaction failed")), - }; + let height = submit_ibc_tx(test_a, msg, ALBERT, ALBERT_KEY, false)?; + let events = get_events(test_a, height)?; + let packet = + get_packet_from_events(&events).ok_or(eyre!("Transaction failed"))?; + let ack = + get_ack_from_events(&events).ok_or(eyre!("Transaction failed"))?; // get the proof on Chain A let height_a = query_height(test_a)?; - let proofs = get_ack_proof(test_a, &packet, height_a)?; + let proof_acked_on_b = get_ack_proof(test_a, &packet, height_a)?; let msg = MsgAcknowledgement { packet, - acknowledgement: acknowledgement.into(), - proofs, - signer: Signer::from_str("test_b").expect("invalid signer"), + acknowledgement: ack.try_into().expect("invalid ack"), + proof_acked_on_b, + proof_height_on_b: height_a, + signer: signer(), }; // Update the client state of Chain A on Chain B update_client_with_height(test_a, test_b, client_id_b, height_a)?; // Acknowledge on Chain B - submit_ibc_tx(test_b, msg, ALBERT)?; + submit_ibc_tx(test_b, msg, ALBERT, ALBERT_KEY, false)?; Ok(()) } @@ -876,7 +798,8 @@ fn transfer_timeout( test_a: &Test, test_b: &Test, client_id_a: &ClientId, - port_channel_id_a: &PortChannelId, + port_id_a: &PortId, + channel_id_a: &ChannelId, ) -> Result<()> { let receiver = find_address(test_b, BERTHA)?; @@ -887,29 +810,33 @@ fn transfer_timeout( &receiver, NAM, &Amount::native_whole(100000), - port_channel_id_a, + ALBERT_KEY, + port_id_a, + channel_id_a, Some(Duration::new(5, 0)), + false, )?; - let packet = match get_event(test_a, height)? { - Some(IbcEvent::SendPacket(event)) => event.packet, - _ => return Err(eyre!("Transaction failed")), - }; + let events = get_events(test_a, height)?; + let packet = + get_packet_from_events(&events).ok_or(eyre!("Transaction failed"))?; // wait for the timeout sleep(5); let height_b = query_height(test_b)?; - let proofs = get_receipt_absence_proof(test_b, &packet, height_b)?; + let proof_unreceived_on_b = + get_receipt_absence_proof(test_b, &packet, height_b)?; let msg = MsgTimeout { - next_sequence_recv: packet.sequence, packet, - proofs, - signer: Signer::from_str("test_a").expect("invalid signer"), + next_seq_recv_on_b: 1.into(), // not used + proof_unreceived_on_b, + proof_height_on_b: height_b, + signer: signer(), }; // Update the client state of Chain B on Chain A update_client_with_height(test_b, test_a, client_id_a, height_b)?; // Timeout on Chain A - submit_ibc_tx(test_a, msg, ALBERT)?; + submit_ibc_tx(test_a, msg, ALBERT, ALBERT_KEY, false)?; Ok(()) } @@ -918,57 +845,45 @@ fn get_commitment_proof( test: &Test, packet: &Packet, target_height: Height, -) -> Result { +) -> Result { // we need proofs at the height of the previous block let query_height = target_height.decrement().unwrap(); let key = commitment_key( - &packet.source_port.as_str().parse().unwrap(), - &packet.source_channel.as_str().parse().unwrap(), - u64::from(packet.sequence).into(), + &packet.port_id_on_a, + &packet.chan_id_on_a, + packet.seq_on_a, ); let (_, tm_proof) = query_value_with_proof(test, &key, Some(query_height))?; - let commitment_proof = convert_proof(tm_proof)?; - - Proofs::new(commitment_proof, None, None, None, target_height) - .map_err(|e| eyre!("Creating proofs failed: error {}", e)) + convert_proof(tm_proof) } fn get_ack_proof( test: &Test, packet: &Packet, target_height: Height, -) -> Result { +) -> Result { // we need proofs at the height of the previous block let query_height = target_height.decrement().unwrap(); - let key = ack_key( - &packet.destination_port.as_str().parse().unwrap(), - &packet.destination_channel.as_str().parse().unwrap(), - u64::from(packet.sequence).into(), - ); + let key = + ack_key(&packet.port_id_on_b, &packet.chan_id_on_b, packet.seq_on_a); let (_, tm_proof) = query_value_with_proof(test, &key, Some(query_height))?; - let ack_proof = convert_proof(tm_proof)?; - - Proofs::new(ack_proof, None, None, None, target_height) - .map_err(|e| eyre!("Creating proofs failed: error {}", e)) + convert_proof(tm_proof) } fn get_receipt_absence_proof( test: &Test, packet: &Packet, target_height: Height, -) -> Result { +) -> Result { // we need proofs at the height of the previous block let query_height = target_height.decrement().unwrap(); let key = receipt_key( - &packet.destination_port.as_str().parse().unwrap(), - &packet.destination_channel.as_str().parse().unwrap(), - u64::from(packet.sequence).into(), + &packet.port_id_on_b, + &packet.chan_id_on_b, + packet.seq_on_a, ); let (_, tm_proof) = query_value_with_proof(test, &key, Some(query_height))?; - let absence_proof = convert_proof(tm_proof)?; - - Proofs::new(absence_proof, None, None, None, target_height) - .map_err(|e| eyre!("Creating proofs failed: error {}", e)) + convert_proof(tm_proof) } fn commitment_prefix() -> CommitmentPrefix { @@ -979,7 +894,9 @@ fn commitment_prefix() -> CommitmentPrefix { fn submit_ibc_tx( test: &Test, message: impl Msg + std::fmt::Debug, + owner: &str, signer: &str, + wait_reveal_pk: bool, ) -> Result { let data_path = test.test_dir.path().join("tx.data"); let data = make_ibc_data(message); @@ -996,7 +913,9 @@ fn submit_ibc_tx( TX_IBC_WASM, "--data-path", &data_path, - "--signer", + "--owner", + owner, + "--signing-keys", signer, "--gas-amount", "0", @@ -1010,6 +929,9 @@ fn submit_ibc_tx( Some(40) )?; client.exp_string("Transaction applied")?; + if wait_reveal_pk { + client.exp_string("Transaction applied")?; + } check_tx_height(test, &mut client) } @@ -1020,23 +942,26 @@ fn transfer( receiver: &Address, token: impl AsRef, amount: &Amount, - port_channel_id: &PortChannelId, + signer: impl AsRef, + port_id: &PortId, + channel_id: &ChannelId, timeout_sec: Option, + wait_reveal_pk: bool, ) -> Result { let rpc = get_actor_rpc(test, &Who::Validator(0)); let receiver = receiver.to_string(); let amount = amount.to_string_native(); - let port_id = port_channel_id.port_id.to_string(); - let channel_id = port_channel_id.channel_id.to_string(); + let channel_id = channel_id.to_string(); + let port_id = port_id.to_string(); let mut tx_args = vec![ "ibc-transfer", "--source", sender.as_ref(), "--receiver", &receiver, - "--signer", - sender.as_ref(), + "--signing-keys", + signer.as_ref(), "--token", token.as_ref(), "--amount", @@ -1057,6 +982,9 @@ fn transfer( let mut client = run!(test, Bin::Client, tx_args, Some(40))?; client.exp_string("Transaction applied")?; + if wait_reveal_pk { + client.exp_string("Transaction applied")?; + } check_tx_height(test, &mut client) } @@ -1127,40 +1055,6 @@ fn query_header(test: &Test, height: Height) -> Result { } } -fn get_event(test: &Test, height: u32) -> Result> { - let rpc = get_actor_rpc(test, &Who::Validator(0)); - let ledger_address = TendermintAddress::from_str(&rpc).unwrap(); - let client = HttpClient::new(ledger_address).unwrap(); - - let response = test - .async_runtime() - .block_on(client.block_results(height)) - .map_err(|e| eyre!("block_results() for an IBC event failed: {}", e))?; - let tx_results = response.txs_results.ok_or_else(|| { - eyre!("No transaction has been executed: height {}", height) - })?; - for result in tx_results { - if result.code.is_err() { - return Err(eyre!( - "The transaction failed: code {:?}, log {}", - result.code, - result.log - )); - } - } - let events = response - .end_block_events - .ok_or_else(|| eyre!("IBC event was not found: height {}", height))?; - for event in &events { - match ibc_event_try_from_abci_event(event) { - Ok(ibc_event) => return Ok(Some(ibc_event)), - Err(_) => continue, - } - } - // No IBC event was found - Ok(None) -} - fn check_ibc_update_query( test: &Test, client_id: &ClientId, @@ -1171,7 +1065,7 @@ fn check_ibc_update_query( let client = HttpClient::new(ledger_address).unwrap(); match test.async_runtime().block_on(RPC.shell().ibc_client_update( &client, - &client_id.as_str().parse().unwrap(), + client_id, &consensus_height, )) { Ok(Some(event)) => { @@ -1194,11 +1088,11 @@ fn check_ibc_packet_query( match test.async_runtime().block_on(RPC.shell().ibc_packet( &client, event_type, - &packet.source_port.as_str().parse().unwrap(), - &packet.source_channel.as_str().parse().unwrap(), - &packet.destination_port.as_str().parse().unwrap(), - &packet.destination_channel.as_str().parse().unwrap(), - &packet.sequence.to_string().parse().unwrap(), + &packet.port_id_on_a, + &packet.chan_id_on_a, + &packet.port_id_on_b, + &packet.chan_id_on_b, + &packet.seq_on_a, )) { Ok(Some(event)) => { println!("Found the packet event: {:?}", event); @@ -1230,8 +1124,19 @@ fn query_value_with_proof( } fn convert_proof(tm_proof: TmProof) -> Result { - let merkle_proof = convert_tm_to_ics_merkle_proof(&tm_proof) - .map_err(|e| eyre!("Proof conversion to MerkleProof failed: {}", e))?; + use namada::ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; + use namada::ibc_proto::ics23::CommitmentProof; + + let mut proofs = Vec::new(); + + for op in &tm_proof.ops { + let mut parsed = CommitmentProof { proof: None }; + prost::Message::merge(&mut parsed, op.data.as_slice()) + .expect("merging CommitmentProof failed"); + proofs.push(parsed); + } + + let merkle_proof = MerkleProof::from(RawMerkleProof { proofs }); CommitmentProofBytes::try_from(merkle_proof).map_err(|e| { eyre!("Proof conversion to CommitmentProofBytes failed: {}", e) }) @@ -1239,7 +1144,8 @@ fn convert_proof(tm_proof: TmProof) -> Result { /// Check balances after IBC transfer fn check_balances( - dest_port_channel_id: &PortChannelId, + dest_port_id: &PortId, + dest_channel_id: &ChannelId, test_a: &Test, test_b: &Test, ) -> Result<()> { @@ -1261,10 +1167,7 @@ fn check_balances( client.assert_success(); // Check the balance on Chain B - let denom = format!( - "{}/{}/{}", - &dest_port_channel_id.port_id, &dest_port_channel_id.channel_id, &token, - ); + let denom = format!("{}/{}/{}", &dest_port_id, &dest_channel_id, &token,); let ibc_token = ibc_token(denom).to_string(); let rpc_b = get_actor_rpc(test_b, &Who::Validator(0)); let query_args = vec![ @@ -1279,15 +1182,13 @@ fn check_balances( /// Check balances after non IBC transfer fn check_balances_after_non_ibc( - port_channel_id: &PortChannelId, + port_id: &PortId, + channel_id: &ChannelId, test: &Test, ) -> Result<()> { // Check the balance on Chain B let token = find_address(test, NAM)?; - let denom = format!( - "{}/{}/{}", - port_channel_id.port_id, port_channel_id.channel_id, token - ); + let denom = format!("{}/{}/{}", port_id, channel_id, token); let ibc_token = ibc_token(denom).to_string(); // Check the source @@ -1314,7 +1215,8 @@ fn check_balances_after_non_ibc( /// Check balances after IBC transfer back fn check_balances_after_back( - dest_port_channel_id: &PortChannelId, + dest_port_id: &PortId, + dest_channel_id: &ChannelId, test_a: &Test, test_b: &Test, ) -> Result<()> { @@ -1336,10 +1238,7 @@ fn check_balances_after_back( client.assert_success(); // Check the balance on Chain B - let denom = format!( - "{}/{}/{}", - &dest_port_channel_id.port_id, &dest_port_channel_id.channel_id, &token, - ); + let denom = format!("{}/{}/{}", dest_port_id, dest_channel_id, &token,); let ibc_token = ibc_token(denom).to_string(); let rpc_b = get_actor_rpc(test_b, &Who::Validator(0)); let query_args = vec![ @@ -1351,3 +1250,146 @@ fn check_balances_after_back( client.assert_success(); Ok(()) } + +fn signer() -> Signer { + "signer".to_string().into() +} + +/// Helper function to make the MsgConnectionOpenTry because it has a private +/// field +fn make_msg_conn_open_try( + client_id: ClientId, + client_state: TmClientState, + counterparty: ConnCounterparty, + conn_proof: CommitmentProofBytes, + client_state_proof: CommitmentProofBytes, + consensus_proof: CommitmentProofBytes, + proofs_height: Height, +) -> MsgConnectionOpenTry { + use namada::ibc_proto::ibc::core::connection::v1::MsgConnectionOpenTry as RawMsgConnectionOpenTry; + + let consensus_height = client_state.latest_height(); + #[allow(deprecated)] + RawMsgConnectionOpenTry { + client_id: client_id.as_str().to_string(), + client_state: Some(client_state.into()), + counterparty: Some(counterparty.into()), + delay_period: 0, + counterparty_versions: vec![ConnVersion::default().into()], + proof_init: conn_proof.into(), + proof_height: Some(proofs_height.into()), + proof_client: client_state_proof.into(), + proof_consensus: consensus_proof.into(), + consensus_height: Some(consensus_height.into()), + signer: "signer".to_string(), + previous_connection_id: ConnectionId::default().to_string(), + } + .try_into() + .expect("invalid message") +} + +fn get_client_id_from_events(events: &Vec) -> Option { + get_attribute_from_events(events, "client_id").map(|v| v.parse().unwrap()) +} + +fn get_connection_id_from_events( + events: &Vec, +) -> Option { + get_attribute_from_events(events, "connection_id") + .map(|v| v.parse().unwrap()) +} + +fn get_channel_id_from_events(events: &Vec) -> Option { + get_attribute_from_events(events, "channel_id").map(|v| v.parse().unwrap()) +} + +fn get_ack_from_events(events: &Vec) -> Option> { + get_attribute_from_events(events, "packet_ack") + .map(|v| Vec::from(v.as_bytes())) +} + +fn get_attribute_from_events( + events: &Vec, + key: &str, +) -> Option { + for event in events { + let attributes = get_attributes_from_event(event); + if let Some(value) = attributes.get(key) { + return Some(value.clone()); + } + } + None +} + +fn get_packet_from_events(events: &Vec) -> Option { + for event in events { + let attributes = get_attributes_from_event(event); + if !attributes.contains_key("packet_src_port") { + continue; + } + let mut packet = Packet::default(); + for (key, val) in attributes { + match key.as_str() { + "packet_src_port" => packet.port_id_on_a = val.parse().unwrap(), + "packet_src_channel" => { + packet.chan_id_on_a = val.parse().unwrap() + } + "packet_dst_port" => packet.port_id_on_b = val.parse().unwrap(), + "packet_dst_channel" => { + packet.chan_id_on_b = val.parse().unwrap() + } + "packet_timeout_height" => { + packet.timeout_height_on_b = match Height::from_str(&val) { + Ok(height) => TimeoutHeight::At(height), + Err(_) => TimeoutHeight::Never, + } + } + "packet_timeout_timestamp" => { + packet.timeout_timestamp_on_b = val.parse().unwrap() + } + "packet_sequence" => { + packet.seq_on_a = u64::from_str(&val).unwrap().into() + } + "packet_data" => packet.data = Vec::from(val.as_bytes()), + _ => {} + } + } + return Some(packet); + } + None +} + +fn get_attributes_from_event(event: &AbciEvent) -> HashMap { + event + .attributes + .iter() + .map(|tag| (tag.key.to_string(), tag.value.to_string())) + .collect() +} + +fn get_events(test: &Test, height: u32) -> Result> { + let rpc = get_actor_rpc(test, &Who::Validator(0)); + let ledger_address = TendermintAddress::from_str(&rpc).unwrap(); + let client = HttpClient::new(ledger_address).unwrap(); + + let response = test + .async_runtime() + .block_on(client.block_results(height)) + .map_err(|e| eyre!("block_results() for an IBC event failed: {}", e))?; + let tx_results = response.txs_results.ok_or_else(|| { + eyre!("No transaction has been executed: height {}", height) + })?; + for result in tx_results { + if result.code.is_err() { + return Err(eyre!( + "The transaction failed: code {:?}, log {}", + result.code, + result.log + )); + } + } + + response + .end_block_events + .ok_or_else(|| eyre!("IBC event was not found: height {}", height)) +} diff --git a/tests/src/e2e/ledger_tests.rs b/tests/src/e2e/ledger_tests.rs index b9e000b9a7..51bf2a4b34 100644 --- a/tests/src/e2e/ledger_tests.rs +++ b/tests/src/e2e/ledger_tests.rs @@ -20,7 +20,6 @@ use borsh::BorshSerialize; use color_eyre::eyre::Result; use data_encoding::HEXLOWER; use namada::types::address::Address; -use namada::types::governance::ProposalType; use namada::types::storage::Epoch; use namada::types::token; use namada_apps::config::ethereum_bridge; @@ -29,18 +28,21 @@ use namada_apps::config::genesis::genesis_config::{ }; use namada_apps::config::utils::convert_tm_addr_to_socket_addr; use namada_apps::facade::tendermint_config::net::Address as TendermintAddress; +use namada_core::ledger::governance::cli::onchain::{PgfAction, PgfSteward}; use namada_test_utils::TestWasms; +use namada_vp_prelude::testnet_pow; use serde_json::json; use setup::constants::*; use setup::Test; use super::helpers::{ - get_height, wait_for_block_height, wait_for_wasm_pre_compile, + epochs_per_year_from_min_duration, get_height, wait_for_block_height, + wait_for_wasm_pre_compile, }; use super::setup::{get_all_wasms_hashes, set_ethereum_bridge_mode, NamadaCmd}; use crate::e2e::helpers::{ epoch_sleep, find_address, find_bonded_stake, get_actor_rpc, get_epoch, - parse_reached_epoch, + is_debug_mode, parse_reached_epoch, }; use crate::e2e::setup::{self, default_port_offset, sleep, Bin, Who}; use crate::{run, run_as}; @@ -170,6 +172,8 @@ fn test_node_connectivity_and_consensus() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + BERTHA_KEY, "--node", &validator_one_rpc, ]; @@ -406,7 +410,22 @@ fn stop_ledger_at_height() -> Result<()> { /// 8. Query the raw bytes of a storage key #[test] fn ledger_txs_and_queries() -> Result<()> { - let test = setup::network(|genesis| genesis, None)?; + let test = setup::network( + |genesis| { + #[cfg(not(feature = "mainnet"))] + { + GenesisConfig { + faucet_pow_difficulty: testnet_pow::Difficulty::try_new(1), + ..genesis + } + } + #[cfg(feature = "mainnet")] + { + genesis + } + }, + None, + )?; set_ethereum_bridge_mode( &test, @@ -441,6 +460,9 @@ fn ledger_txs_and_queries() -> Result<()> { let validator_one_rpc = get_actor_rpc(&test, &Who::Validator(0)); + let multisig_account = + format!("{},{},{}", BERTHA_KEY, ALBERT_KEY, CHRISTEL_KEY); + let txs_args = vec![ // 2. Submit a token transfer tx (from an established account) vec![ @@ -459,6 +481,8 @@ fn ledger_txs_and_queries() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + BERTHA_KEY, "--node", &validator_one_rpc, ], @@ -479,6 +503,8 @@ fn ledger_txs_and_queries() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + DAEWON, "--node", &validator_one_rpc, ], @@ -505,46 +531,50 @@ fn ledger_txs_and_queries() -> Result<()> { // 3. Submit a transaction to update an account's validity // predicate vec![ - "update", - "--address", - BERTHA, - "--code-path", - VP_USER_WASM, - "--gas-amount", - "0", - "--gas-limit", - "0", - "--gas-token", - NAM, + "update-account", + "--address", + BERTHA, + "--code-path", + VP_USER_WASM, + "--gas-amount", + "0", + "--gas-limit", + "0", + "--gas-token", + NAM, + "--signing-keys", + BERTHA_KEY, "--node", &validator_one_rpc, ], // 4. Submit a custom tx vec![ "tx", - "--signer", - BERTHA, "--code-path", TX_TRANSFER_WASM, "--data-path", &tx_data_path, + "--owner", + BERTHA, "--gas-amount", "0", "--gas-limit", "0", "--gas-token", NAM, + "--signing-keys", + BERTHA_KEY, "--node", &validator_one_rpc ], // 5. Submit a tx to initialize a new account vec![ "init-account", - "--source", - BERTHA, - "--public-key", + "--public-keys", // Value obtained from `namada::types::key::ed25519::tests::gen_keypair` "001be519a321e29020fa3cbfbfd01bd5e92db134305609270b71dace25b5a21168", + "--threshold", + "1", "--code-path", VP_USER_WASM, "--alias", @@ -555,11 +585,35 @@ fn ledger_txs_and_queries() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + BERTHA_KEY, "--node", &validator_one_rpc, ], - // 6. Submit a tx to withdraw from faucet account (requires PoW challenge - // solution) + // 5. Submit a tx to initialize a new multisig account + vec![ + "init-account", + "--public-keys", + &multisig_account, + "--threshold", + "2", + "--code-path", + VP_USER_WASM, + "--alias", + "Test-Account-2", + "--gas-amount", + "0", + "--gas-limit", + "0", + "--gas-token", + NAM, + "--signing-keys", + BERTHA_KEY, + "--node", + &validator_one_rpc, + ], + // 6. Submit a tx to withdraw from faucet account (requires PoW challenge + // solution) vec![ "transfer", "--source", @@ -571,8 +625,8 @@ fn ledger_txs_and_queries() -> Result<()> { "--amount", "10.1", // Faucet withdrawal requires an explicit signer - "--signer", - ALBERT, + "--signing-keys", + ALBERT_KEY, "--node", &validator_one_rpc, ], @@ -612,6 +666,8 @@ fn ledger_txs_and_queries() -> Result<()> { ], // expect a decimal vec![r"nam: \d+(\.\d+)?"], + // check also as validator node + true, ), // Unspecified token expect all tokens from wallet derived from genesis ( @@ -625,9 +681,25 @@ fn ledger_txs_and_queries() -> Result<()> { r"kartoffel: \d+(\.\d+)?", r"schnitzel: \d+(\.\d+)?", ], + // check also as validator node + true, + ), + ( + vec![ + "query-account", + "--owner", + "Test-Account-2", + "--node", + &validator_one_rpc, + ], + vec!["Threshold: 2"], + // check also as validator node + false, ), ]; - for (query_args, expected) in &query_args_and_expected_response { + for (query_args, expected, check_as_validator) in + &query_args_and_expected_response + { // Run as a non-validator let mut client = run!(test, Bin::Client, query_args, Some(40))?; for pattern in expected { @@ -635,6 +707,10 @@ fn ledger_txs_and_queries() -> Result<()> { } client.assert_success(); + if !check_as_validator { + continue; + } + // Run as a validator let mut client = run_as!( test, @@ -707,9 +783,7 @@ fn invalid_transactions() -> Result<()> { let tx_args = vec![ "transfer", "--source", - DAEWON, - "--signing-key", - ALBERT_KEY, + BERTHA, "--target", ALBERT, "--token", @@ -722,8 +796,11 @@ fn invalid_transactions() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + ALBERT_KEY, "--node", &validator_one_rpc, + "--force", ]; let mut client = run!(test, Bin::Client, tx_args, Some(40))?; @@ -756,13 +833,16 @@ fn invalid_transactions() -> Result<()> { ledger.exp_string("Committed block hash")?; let _bg_ledger = ledger.background(); + // we need to wait for the rpc endpoint to start + sleep(10); + // 5. Submit an invalid transactions (invalid token address) let daewon_lower = DAEWON.to_lowercase(); let tx_args = vec![ "transfer", "--source", DAEWON, - "--signing-key", + "--signing-keys", &daewon_lower, "--target", ALBERT, @@ -859,6 +939,8 @@ fn pos_bonds() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + "validator-0-account-key", "--node", &validator_one_rpc, ]; @@ -883,6 +965,8 @@ fn pos_bonds() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + BERTHA_KEY, "--node", &validator_one_rpc, ]; @@ -904,6 +988,8 @@ fn pos_bonds() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + "validator-0-account-key", "--node", &validator_one_rpc, ]; @@ -928,6 +1014,8 @@ fn pos_bonds() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + BERTHA_KEY, "--node", &validator_one_rpc, ]; @@ -947,7 +1035,7 @@ fn pos_bonds() -> Result<()> { epoch, delegation_withdrawable_epoch ); let start = Instant::now(); - let loop_timeout = Duration::new(60, 0); + let loop_timeout = Duration::new(120, 0); loop { if Instant::now().duration_since(start) > loop_timeout { panic!( @@ -972,6 +1060,8 @@ fn pos_bonds() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + "validator-0-account-key", "--node", &validator_one_rpc, ]; @@ -994,6 +1084,8 @@ fn pos_bonds() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + BERTHA_KEY, "--node", &validator_one_rpc, ]; @@ -1070,6 +1162,8 @@ fn pos_rewards() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + BERTHA_KEY, "--ledger-address", &validator_zero_rpc, ]; @@ -1106,6 +1200,8 @@ fn pos_rewards() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + "validator-1-account-key", "--ledger-address", &validator_one_rpc, ]; @@ -1128,6 +1224,8 @@ fn pos_rewards() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + "validator-2-account-key", "--ledger-address", &validator_two_rpc, ]; @@ -1216,6 +1314,8 @@ fn test_bond_queries() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + BERTHA_KEY, "--ledger-address", &validator_one_rpc, ]; @@ -1252,6 +1352,8 @@ fn test_bond_queries() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + BERTHA_KEY, "--ledger-address", &validator_one_rpc, ]; @@ -1275,6 +1377,8 @@ fn test_bond_queries() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + BERTHA_KEY, "--ledger-address", &validator_one_rpc, ]; @@ -1368,14 +1472,13 @@ fn pos_init_validator() -> Result<()> { // 2. Initialize a new validator account with the non-validator node let new_validator = "new-validator"; - let new_validator_key = format!("{}-key", new_validator); + let _new_validator_key = format!("{}-key", new_validator); let tx_args = vec![ "init-validator", "--alias", new_validator, - "--source", - BERTHA, - "--unsafe-dont-encrypt", + "--account-keys", + "bertha-key", "--gas-amount", "0", "--gas-limit", @@ -1386,8 +1489,11 @@ fn pos_init_validator() -> Result<()> { "0.05", "--max-commission-rate-change", "0.01", + "--signing-keys", + "bertha-key", "--node", &non_validator_rpc, + "--unsafe-dont-encrypt", ]; let mut client = run!(test, Bin::Client, tx_args, Some(40))?; client.exp_string("Transaction is valid.")?; @@ -1400,7 +1506,7 @@ fn pos_init_validator() -> Result<()> { "--source", BERTHA, "--target", - &new_validator_key, + new_validator, "--token", NAM, "--amount", @@ -1411,6 +1517,8 @@ fn pos_init_validator() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + BERTHA_KEY, "--node", &non_validator_rpc, ]; @@ -1434,6 +1542,8 @@ fn pos_init_validator() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + BERTHA_KEY, "--node", &non_validator_rpc, ]; @@ -1459,6 +1569,8 @@ fn pos_init_validator() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + BERTHA_KEY, "--node", &non_validator_rpc, ]; @@ -1491,6 +1603,13 @@ fn pos_init_validator() -> Result<()> { non_validator.interrupt()?; non_validator.exp_eof()?; + // it takes a bit before the node is shutdown. We dont want flasky test. + if is_debug_mode() { + sleep(10); + } else { + sleep(5); + } + let loc = format!("{}:{}", std::file!(), std::line!()); let validator_1_base_dir = test.get_base_dir(&Who::NonValidator); let mut validator_1 = setup::run_cmd( @@ -1582,6 +1701,8 @@ fn ledger_many_txs_in_a_block() -> Result<()> { "0", "--gas-token", NAM, + "--signing-keys", + BERTHA_KEY, "--node", ]); @@ -1702,12 +1823,8 @@ fn proposal_submission() -> Result<()> { let valid_proposal_json_path = prepare_proposal_data( &test, albert, - ProposalType::Default(Some( - TestWasms::TxProposalCode - .path() - .to_string_lossy() - .to_string(), - )), + TestWasms::TxProposalCode.read_bytes(), + 12, ); let validator_one_rpc = get_actor_rpc(&test, &Who::Validator(0)); @@ -1737,7 +1854,7 @@ fn proposal_submission() -> Result<()> { ]; let mut client = run!(test, Bin::Client, proposal_query_args, Some(40))?; - client.exp_string("Proposal: 0")?; + client.exp_string("Proposal Id: 0")?; client.assert_success(); // 4. Query token balance proposal author (submitted funds) @@ -1773,66 +1890,28 @@ fn proposal_submission() -> Result<()> { // 6. Submit an invalid proposal // proposal is invalid due to voting_end_epoch - voting_start_epoch < 3 let albert = find_address(&test, ALBERT)?; - let invalid_proposal_json = json!( - { - "content": { - "title": "TheTitle", - "authors": "test@test.com", - "discussions-to": "www.github.com/anoma/aip/1", - "created": "2022-03-10T08:54:37Z", - "license": "MIT", - "abstract": "Ut convallis eleifend orci vel venenatis. Duis - vulputate metus in lacus sollicitudin vestibulum. Suspendisse vel velit - ac est consectetur feugiat nec ac urna. Ut faucibus ex nec dictum - fermentum. Morbi aliquet purus at sollicitudin ultrices. Quisque viverra - varius cursus. Praesent sed mauris gravida, pharetra turpis non, gravida - eros. Nullam sed ex justo. Ut at placerat ipsum, sit amet rhoncus libero. - Sed blandit non purus non suscipit. Phasellus sed quam nec augue bibendum - bibendum ut vitae urna. Sed odio diam, ornare nec sapien eget, congue - viverra enim.", - "motivation": "Ut convallis eleifend orci vel venenatis. Duis - vulputate metus in lacus sollicitudin vestibulum. Suspendisse vel velit - ac est consectetur feugiat nec ac urna. Ut faucibus ex nec dictum - fermentum. Morbi aliquet purus at sollicitudin ultrices.", - "details": "Ut convallis eleifend orci vel venenatis. Duis - vulputate metus in lacus sollicitudin vestibulum. Suspendisse vel velit - ac est consectetur feugiat nec ac urna. Ut faucibus ex nec dictum - fermentum. Morbi aliquet purus at sollicitudin ultrices. Quisque viverra - varius cursus. Praesent sed mauris gravida, pharetra turpis non, gravida - eros.", "requires": "2" - }, - "author": albert, - "voting_start_epoch": 9999_u64, - "voting_end_epoch": 10000_u64, - "grace_epoch": 10009_u64, - "type": { - "Default":null - } - } - ); - let invalid_proposal_json_path = - test.test_dir.path().join("invalid_proposal.json"); - generate_proposal_json_file( - invalid_proposal_json_path.as_path(), - &invalid_proposal_json, + let invalid_proposal_json = prepare_proposal_data( + &test, + albert, + TestWasms::TxProposalCode.read_bytes(), + 1, ); let submit_proposal_args = vec![ "init-proposal", "--data-path", - invalid_proposal_json_path.to_str().unwrap(), + invalid_proposal_json.to_str().unwrap(), "--node", &validator_one_rpc, ]; let mut client = run!(test, Bin::Client, submit_proposal_args, Some(40))?; - client.exp_string( - "Invalid proposal end epoch: difference between proposal start and \ - end epoch must be at least 3 and at max 27 and end epoch must be a \ - multiple of 3", + client.exp_regex( + "Proposal data are invalid: Invalid proposal start epoch: 1 must be \ + greater than current epoch .* and a multiple of 3", )?; client.assert_failure(); - // 7. Check invalid proposal was not accepted + // 7. Check invalid proposal was not submitted let proposal_query_args = vec![ "query-proposal", "--proposal-id", @@ -1842,7 +1921,7 @@ fn proposal_submission() -> Result<()> { ]; let mut client = run!(test, Bin::Client, proposal_query_args, Some(40))?; - client.exp_string("No valid proposal was found with id 1")?; + client.exp_string("No proposal found with id: 1")?; client.assert_success(); // 8. Query token balance (funds shall not be submitted) @@ -1873,7 +1952,7 @@ fn proposal_submission() -> Result<()> { "0", "--vote", "yay", - "--signer", + "--address", "validator-0", "--node", &validator_one_rpc, @@ -1895,7 +1974,7 @@ fn proposal_submission() -> Result<()> { "0", "--vote", "nay", - "--signer", + "--address", BERTHA, "--node", &validator_one_rpc, @@ -1913,7 +1992,7 @@ fn proposal_submission() -> Result<()> { "0", "--vote", "yay", - "--signer", + "--address", ALBERT, "--node", &validator_one_rpc, @@ -1941,7 +2020,10 @@ fn proposal_submission() -> Result<()> { ]; let mut client = run!(test, Bin::Client, query_proposal, Some(15))?; - client.exp_string("Result: passed")?; + client.exp_string("Proposal Id: 0")?; + client.exp_string( + "passed with 200900.000000 yay votes and 0.000000 nay votes (0.%)", + )?; client.assert_success(); // 12. Wait proposal grace and check proposal author funds @@ -1992,228 +2074,6 @@ fn proposal_submission() -> Result<()> { Ok(()) } -/// Test submission and vote of an ETH proposal. -/// -/// 1 - Submit proposal -/// 2 - Vote with delegator and check failure -/// 3 - Vote with validator and check success -/// 4 - Check that proposal passed and funds -#[test] -fn eth_governance_proposal() -> Result<()> { - let test = setup::network( - |genesis| { - let parameters = ParametersConfig { - epochs_per_year: epochs_per_year_from_min_duration(1), - max_proposal_bytes: Default::default(), - min_num_of_blocks: 1, - max_expected_time_per_block: 1, - ..genesis.parameters - }; - - GenesisConfig { - parameters, - ..genesis - } - }, - None, - )?; - - let namadac_help = vec!["--help"]; - - let mut client = run!(test, Bin::Client, namadac_help, Some(40))?; - client.exp_string("Namada client command line interface.")?; - client.assert_success(); - - // Run the ledger node - let _bg_ledger = - start_namada_ledger_node_wait_wasm(&test, Some(0), Some(40))? - .background(); - - let validator_one_rpc = get_actor_rpc(&test, &Who::Validator(0)); - - // Delegate some token - let tx_args = vec![ - "bond", - "--validator", - "validator-0", - "--source", - BERTHA, - "--amount", - "900", - "--gas-amount", - "0", - "--gas-limit", - "0", - "--gas-token", - NAM, - "--ledger-address", - &validator_one_rpc, - ]; - client = run!(test, Bin::Client, tx_args, Some(40))?; - client.exp_string("Transaction is valid.")?; - client.assert_success(); - - // 1 - Submit proposal - let albert = find_address(&test, ALBERT)?; - let valid_proposal_json_path = - prepare_proposal_data(&test, albert, ProposalType::ETHBridge); - let validator_one_rpc = get_actor_rpc(&test, &Who::Validator(0)); - - let submit_proposal_args = vec![ - "init-proposal", - "--data-path", - valid_proposal_json_path.to_str().unwrap(), - "--ledger-address", - &validator_one_rpc, - ]; - client = run!(test, Bin::Client, submit_proposal_args, Some(40))?; - client.exp_string("Transaction is valid.")?; - client.assert_success(); - - // Query the proposal - let proposal_query_args = vec![ - "query-proposal", - "--proposal-id", - "0", - "--ledger-address", - &validator_one_rpc, - ]; - - client = run!(test, Bin::Client, proposal_query_args, Some(40))?; - client.exp_string("Proposal: 0")?; - client.assert_success(); - - // Query token balance proposal author (submitted funds) - let query_balance_args = vec![ - "balance", - "--owner", - ALBERT, - "--token", - NAM, - "--ledger-address", - &validator_one_rpc, - ]; - - client = run!(test, Bin::Client, query_balance_args, Some(40))?; - client.exp_string("nam: 999500")?; - client.assert_success(); - - // Query token balance governance - let query_balance_args = vec![ - "balance", - "--owner", - GOVERNANCE_ADDRESS, - "--token", - NAM, - "--ledger-address", - &validator_one_rpc, - ]; - - client = run!(test, Bin::Client, query_balance_args, Some(40))?; - client.exp_string("nam: 500")?; - client.assert_success(); - - // 2 - Vote with delegator and check failure - let mut epoch = get_epoch(&test, &validator_one_rpc).unwrap(); - while epoch.0 <= 13 { - sleep(1); - epoch = get_epoch(&test, &validator_one_rpc).unwrap(); - } - - use namada::types::key::{self, secp256k1, SigScheme}; - use rand::prelude::ThreadRng; - use rand::thread_rng; - - // Generate a signing key to sign the eth message to sign the eth message to - // sign the eth message - let mut rng: ThreadRng = thread_rng(); - let node_sk = secp256k1::SigScheme::generate(&mut rng); - let signing_key = key::common::SecretKey::Secp256k1(node_sk); - let msg = "fd34672ab5"; - let vote_arg = format!("{} {}", signing_key, msg); - let submit_proposal_vote_delagator = vec![ - "vote-proposal", - "--proposal-id", - "0", - "--vote", - "yay", - "--eth", - &vote_arg, - "--signer", - BERTHA, - "--ledger-address", - &validator_one_rpc, - ]; - - client = run!(test, Bin::Client, submit_proposal_vote_delagator, Some(40))?; - client.exp_string("Transaction is invalid.")?; - client.assert_success(); - - // 3 - Send a yay vote from a validator - let vote_arg = format!("{} {}", signing_key, msg); - - let submit_proposal_vote = vec![ - "vote-proposal", - "--proposal-id", - "0", - "--vote", - "yay", - "--eth", - &vote_arg, - "--signer", - "validator-0", - "--ledger-address", - &validator_one_rpc, - ]; - - client = run_as!( - test, - Who::Validator(0), - Bin::Client, - submit_proposal_vote, - Some(15) - )?; - client.exp_string("Transaction is valid.")?; - client.assert_success(); - - // 4 - Wait proposals grace and check proposal author funds - while epoch.0 < 31 { - sleep(1); - epoch = get_epoch(&test, &validator_one_rpc).unwrap(); - } - - let query_balance_args = vec![ - "balance", - "--owner", - ALBERT, - "--token", - NAM, - "--ledger-address", - &validator_one_rpc, - ]; - - client = run!(test, Bin::Client, query_balance_args, Some(30))?; - client.exp_string("nam: 1000000")?; - client.assert_success(); - - // Check if governance funds are 0 - let query_balance_args = vec![ - "balance", - "--owner", - GOVERNANCE_ADDRESS, - "--token", - NAM, - "--ledger-address", - &validator_one_rpc, - ]; - - client = run!(test, Bin::Client, query_balance_args, Some(30))?; - client.exp_string("nam: 0")?; - client.assert_success(); - - Ok(()) -} - /// Test submission and vote of a PGF proposal /// /// 1 - Sumbit two proposals @@ -2287,12 +2147,18 @@ fn pgf_governance_proposal() -> Result<()> { // 1 - Submit proposal let albert = find_address(&test, ALBERT)?; + let pgf_stewards = PgfSteward { + action: PgfAction::Add, + address: albert.clone(), + }; + let valid_proposal_json_path = - prepare_proposal_data(&test, albert.clone(), ProposalType::PGFCouncil); + prepare_proposal_data(&test, albert, vec![pgf_stewards], 12); let validator_one_rpc = get_actor_rpc(&test, &Who::Validator(0)); let submit_proposal_args = vec![ "init-proposal", + "--pgf-stewards", "--data-path", valid_proposal_json_path.to_str().unwrap(), "--ledger-address", @@ -2303,22 +2169,6 @@ fn pgf_governance_proposal() -> Result<()> { client.exp_string("Transaction is valid.")?; client.assert_success(); - // Sumbit another proposal - let valid_proposal_json_path = - prepare_proposal_data(&test, albert, ProposalType::PGFCouncil); - let validator_one_rpc = get_actor_rpc(&test, &Who::Validator(0)); - - let submit_proposal_args = vec![ - "init-proposal", - "--data-path", - valid_proposal_json_path.to_str().unwrap(), - "--ledger-address", - &validator_one_rpc, - ]; - client = run!(test, Bin::Client, submit_proposal_args, Some(40))?; - client.exp_string("Transaction is valid.")?; - client.assert_success(); - // 2 - Query the proposal let proposal_query_args = vec![ "query-proposal", @@ -2329,19 +2179,7 @@ fn pgf_governance_proposal() -> Result<()> { ]; client = run!(test, Bin::Client, proposal_query_args, Some(40))?; - client.exp_string("Proposal: 0")?; - client.assert_success(); - - let proposal_query_args = vec![ - "query-proposal", - "--proposal-id", - "1", - "--ledger-address", - &validator_one_rpc, - ]; - - client = run!(test, Bin::Client, proposal_query_args, Some(40))?; - client.exp_string("Proposal: 1")?; + client.exp_string("Proposal Id: 0")?; client.assert_success(); // Query token balance proposal author (submitted funds) @@ -2356,7 +2194,7 @@ fn pgf_governance_proposal() -> Result<()> { ]; client = run!(test, Bin::Client, query_balance_args, Some(40))?; - client.exp_string("nam: 999000")?; + client.exp_string("nam: 999500")?; client.assert_success(); // Query token balance governance @@ -2371,7 +2209,7 @@ fn pgf_governance_proposal() -> Result<()> { ]; client = run!(test, Bin::Client, query_balance_args, Some(40))?; - client.exp_string("nam: 1000")?; + client.exp_string("nam: 500")?; client.assert_success(); // 3 - Send a yay vote from a validator @@ -2382,17 +2220,13 @@ fn pgf_governance_proposal() -> Result<()> { } let albert_address = find_address(&test, ALBERT)?; - let arg_vote = format!("{} 1000", albert_address); - let submit_proposal_vote = vec![ "vote-proposal", "--proposal-id", "0", "--vote", "yay", - "--pgf", - &arg_vote, - "--signer", + "--address", "validator-0", "--ledger-address", &validator_one_rpc, @@ -2410,16 +2244,13 @@ fn pgf_governance_proposal() -> Result<()> { client.assert_success(); // Send different yay vote from delegator to check majority on 1/3 - let different_vote = format!("{} 900", albert_address); let submit_proposal_vote_delagator = vec![ "vote-proposal", "--proposal-id", "0", "--vote", "yay", - "--pgf", - &different_vote, - "--signer", + "--address", BERTHA, "--ledger-address", &validator_one_rpc, @@ -2431,29 +2262,6 @@ fn pgf_governance_proposal() -> Result<()> { client.exp_string("Transaction is valid.")?; client.assert_success(); - // Send vote to the second proposal from delegator - let submit_proposal_vote_delagator = vec![ - "vote-proposal", - "--proposal-id", - "1", - "--vote", - "yay", - "--pgf", - &different_vote, - "--signer", - BERTHA, - "--ledger-address", - &validator_one_rpc, - ]; - - // this is valid because the client filter ALBERT delegation and there are - // none - let mut client = - run!(test, Bin::Client, submit_proposal_vote_delagator, Some(15))?; - client.exp_string("Transaction applied with result:")?; - client.exp_string("Transaction is valid.")?; - client.assert_success(); - // 4 - Query the proposal and check the result is the one voted by the // validator (majority) epoch = get_epoch(&test, &validator_one_rpc).unwrap(); @@ -2471,23 +2279,7 @@ fn pgf_governance_proposal() -> Result<()> { ]; client = run!(test, Bin::Client, query_proposal, Some(15))?; - client.exp_string(&format!( - "Result: passed with PGF council address: {}, spending cap: 0.001", - albert_address - ))?; - client.assert_success(); - - // Query the second proposal and check the it didn't pass - let query_proposal = vec![ - "query-proposal-result", - "--proposal-id", - "1", - "--ledger-address", - &validator_one_rpc, - ]; - - client = run!(test, Bin::Client, query_proposal, Some(15))?; - client.exp_string("Result: rejected")?; + client.exp_string("passed")?; client.assert_success(); // 12. Wait proposals grace and check proposal author funds @@ -2507,7 +2299,7 @@ fn pgf_governance_proposal() -> Result<()> { ]; client = run!(test, Bin::Client, query_balance_args, Some(30))?; - client.exp_string("nam: 999500")?; + client.exp_string("nam: 1000000")?; client.assert_success(); // Check if governance funds are 0 @@ -2525,6 +2317,15 @@ fn pgf_governance_proposal() -> Result<()> { client.exp_string("nam: 0")?; client.assert_success(); + // 14. Query pgf stewards + let query_pgf = vec!["query-pgf", "--node", &validator_one_rpc]; + + let mut client = run!(test, Bin::Client, query_pgf, Some(30))?; + client.exp_string("Pgf stewards:")?; + client.exp_string(&format!("- {}", albert_address))?; + client.exp_string("Pgf fundings: no fundings are currently set.")?; + client.assert_success(); + Ok(()) } @@ -2602,7 +2403,7 @@ fn proposal_offline() -> Result<()> { client.exp_string("Transaction is valid.")?; client.assert_success(); - // 2. Create an offline + // 2. Create an offline proposal let albert = find_address(&test, ALBERT)?; let valid_proposal_json = json!( { @@ -2618,12 +2419,7 @@ fn proposal_offline() -> Result<()> { "requires": "2" }, "author": albert, - "voting_start_epoch": 3_u64, - "voting_end_epoch": 9_u64, - "grace_epoch": 18_u64, - "type": { - "Default": null - } + "tally_epoch": 3_u64, } ); let valid_proposal_json_path = @@ -2633,6 +2429,12 @@ fn proposal_offline() -> Result<()> { &valid_proposal_json, ); + let mut epoch = get_epoch(&test, &validator_one_rpc).unwrap(); + while epoch.0 <= 3 { + sleep(1); + epoch = get_epoch(&test, &validator_one_rpc).unwrap(); + } + let validator_one_rpc = get_actor_rpc(&test, &Who::Validator(0)); let offline_proposal_args = vec![ @@ -2640,44 +2442,48 @@ fn proposal_offline() -> Result<()> { "--data-path", valid_proposal_json_path.to_str().unwrap(), "--offline", + "--signing-keys", + ALBERT_KEY, + "--output-folder-path", + test.test_dir.path().to_str().unwrap(), "--node", &validator_one_rpc, ]; let mut client = run!(test, Bin::Client, offline_proposal_args, Some(15))?; - client.exp_string("Proposal created: ")?; + let (_, matched) = client.exp_regex("Proposal serialized to: .*")?; client.assert_success(); - // 3. Generate an offline yay vote - let mut epoch = get_epoch(&test, &validator_one_rpc).unwrap(); - while epoch.0 <= 2 { - sleep(1); - epoch = get_epoch(&test, &validator_one_rpc).unwrap(); - } - - let proposal_path = test.test_dir.path().join("proposal"); + let proposal_path = matched + .split(':') + .collect::>() + .get(1) + .unwrap() + .trim() + .to_string(); + // 3. Generate an offline yay vote let submit_proposal_vote = vec![ "vote-proposal", "--data-path", - proposal_path.to_str().unwrap(), + &proposal_path, "--vote", "yay", - "--signer", + "--address", ALBERT, "--offline", + "--signing-keys", + ALBERT_KEY, + "--output-folder-path", + test.test_dir.path().to_str().unwrap(), "--node", &validator_one_rpc, ]; let mut client = run!(test, Bin::Client, submit_proposal_vote, Some(15))?; - client.exp_string("Proposal vote created: ")?; + client.exp_string("Proposal vote serialized to: ")?; client.assert_success(); - let expected_file_name = format!("proposal-vote-{}", albert); - let expected_path_vote = test.test_dir.path().join(expected_file_name); - assert!(expected_path_vote.exists()); - // 4. Compute offline tally let tally_offline = vec![ "query-proposal-result", @@ -2689,7 +2495,8 @@ fn proposal_offline() -> Result<()> { ]; let mut client = run!(test, Bin::Client, tally_offline, Some(15))?; - client.exp_string("Result: rejected")?; + client.exp_string("Parsed 1 votes")?; + client.exp_string("rejected with 900.000000 yay votes")?; client.assert_success(); Ok(()) @@ -3472,6 +3279,8 @@ fn implicit_account_reveal_pk() -> Result<()> { NAM, "--amount", "10.1", + "--signing-keys", + source, "--node", &validator_0_rpc, ] @@ -3489,6 +3298,8 @@ fn implicit_account_reveal_pk() -> Result<()> { source, "--amount", "10.1", + "--signing-keys", + source, "--node", &validator_0_rpc, ] @@ -3499,16 +3310,19 @@ fn implicit_account_reveal_pk() -> Result<()> { // Submit proposal Box::new(|source| { // Gen data for proposal tx - let source = find_address(&test, source).unwrap(); + let author = find_address(&test, source).unwrap(); let valid_proposal_json_path = prepare_proposal_data( &test, - source, - ProposalType::Default(None), + author, + TestWasms::TxProposalCode.read_bytes(), + 12, ); vec![ "init-proposal", "--data-path", valid_proposal_json_path.to_str().unwrap(), + "--signing-keys", + source, "--node", &validator_0_rpc, ] @@ -3544,6 +3358,8 @@ fn implicit_account_reveal_pk() -> Result<()> { NAM, "--amount", "1000", + "--signing-keys", + BERTHA_KEY, "--node", &validator_0_rpc, ]; @@ -3617,10 +3433,11 @@ fn test_epoch_sleep() -> Result<()> { fn prepare_proposal_data( test: &setup::Test, source: Address, - proposal_type: ProposalType, + data: impl serde::Serialize, + start_epoch: u64, ) -> PathBuf { - let valid_proposal_json = json!( - { + let valid_proposal_json = json!({ + "proposal": { "content": { "title": "TheTitle", "authors": "test@test.com", @@ -3633,12 +3450,13 @@ fn prepare_proposal_data( "requires": "2" }, "author": source, - "voting_start_epoch": 12_u64, + "voting_start_epoch": start_epoch, "voting_end_epoch": 24_u64, "grace_epoch": 30_u64, - "type": proposal_type - } - ); + }, + "data": data + }); + let valid_proposal_json_path = test.test_dir.path().join("valid_proposal.json"); generate_proposal_json_file( @@ -3647,9 +3465,3 @@ fn prepare_proposal_data( ); valid_proposal_json_path } - -/// Convert epoch `min_duration` in seconds to `epochs_per_year` genesis -/// parameter. -fn epochs_per_year_from_min_duration(min_duration: u64) -> u64 { - 60 * 60 * 24 * 365 / min_duration -} diff --git a/tests/src/e2e/multitoken_tests.rs b/tests/src/e2e/multitoken_tests.rs new file mode 100644 index 0000000000..5d713b2aed --- /dev/null +++ b/tests/src/e2e/multitoken_tests.rs @@ -0,0 +1,372 @@ +//! Tests for multitoken functionality +use color_eyre::eyre::Result; +use namada_core::types::token; + +use super::helpers::get_actor_rpc; +use super::setup::constants::{ALBERT, BERTHA}; +use super::setup::{self, Who}; +use crate::e2e; +use crate::e2e::setup::constants::{ALBERT_KEY, BERTHA_KEY, CHRISTEL_KEY}; + +mod helpers; + +#[test] +fn test_multitoken_transfer_implicit_to_implicit() -> Result<()> { + let (test, _ledger) = e2e::helpers::setup_single_node_test()?; + + let rpc_addr = get_actor_rpc(&test, &Who::Validator(0)); + let multitoken_alias = helpers::init_multitoken_vp(&test, &rpc_addr)?; + + // establish a multitoken VP with the following balances + // - #atest5blah/tokens/red/balance/$albert_established = 100 + // - #atest5blah/tokens/red/balance/$bertha = 0 + + let multitoken_vp_addr = + e2e::helpers::find_address(&test, &multitoken_alias)?; + println!("Fake multitoken VP established at {}", multitoken_vp_addr); + + let albert_addr = e2e::helpers::find_address(&test, ALBERT)?; + let albert_starting_red_balance = token::Amount::native_whole(100_000_000); + helpers::mint_red_tokens( + &test, + &rpc_addr, + &multitoken_vp_addr, + &albert_addr, + &albert_starting_red_balance, + )?; + + let transfer_amount = token::Amount::native_whole(10_000_000); + + // make a transfer from Albert to Bertha, signed by Christel - this should + // be rejected + let mut unauthorized_transfer = helpers::attempt_red_tokens_transfer( + &test, + &rpc_addr, + &multitoken_alias, + ALBERT, + BERTHA, + CHRISTEL_KEY, + &transfer_amount, + )?; + unauthorized_transfer.exp_string("Transaction applied with result")?; + unauthorized_transfer.exp_string("Transaction is invalid")?; + unauthorized_transfer.exp_string(&format!("Rejected: {albert_addr}"))?; + unauthorized_transfer.assert_success(); + + let albert_balance = helpers::fetch_red_token_balance( + &test, + &rpc_addr, + &multitoken_alias, + ALBERT, + )?; + assert_eq!(albert_balance, albert_starting_red_balance); + + // make a transfer from Albert to Bertha, signed by Albert - this should + // be accepted + let mut authorized_transfer = helpers::attempt_red_tokens_transfer( + &test, + &rpc_addr, + &multitoken_alias, + ALBERT, + BERTHA, + ALBERT_KEY, + &token::Amount::native_whole(10_000_000), + )?; + authorized_transfer.exp_string("Transaction applied with result")?; + authorized_transfer.exp_string("Transaction is valid")?; + authorized_transfer.assert_success(); + + let albert_balance = helpers::fetch_red_token_balance( + &test, + &rpc_addr, + &multitoken_alias, + ALBERT, + )?; + assert_eq!( + albert_balance, + albert_starting_red_balance - transfer_amount + ); + Ok(()) +} + +#[test] +fn test_multitoken_transfer_established_to_implicit() -> Result<()> { + let (test, _ledger) = e2e::helpers::setup_single_node_test()?; + + let rpc_addr = get_actor_rpc(&test, &Who::Validator(0)); + let multitoken_alias = helpers::init_multitoken_vp(&test, &rpc_addr)?; + + let multitoken_vp_addr = + e2e::helpers::find_address(&test, &multitoken_alias)?; + println!("Fake multitoken VP established at {}", multitoken_vp_addr); + + // create an established account that Albert controls + let established_alias = "established"; + e2e::helpers::init_established_account( + &test, + &rpc_addr, + ALBERT, + ALBERT_KEY, + established_alias, + )?; + + let established_starting_red_balance = + token::Amount::native_whole(100_000_000); + // mint some red tokens for the established account + let established_addr = + e2e::helpers::find_address(&test, established_alias)?; + helpers::mint_red_tokens( + &test, + &rpc_addr, + &multitoken_vp_addr, + &established_addr, + &established_starting_red_balance, + )?; + + let transfer_amount = token::Amount::native_whole(10_000_000); + // attempt an unauthorized transfer to Albert from the established account + let mut unauthorized_transfer = helpers::attempt_red_tokens_transfer( + &test, + &rpc_addr, + &multitoken_alias, + established_alias, + BERTHA, + CHRISTEL_KEY, + &transfer_amount, + )?; + unauthorized_transfer.exp_string("Transaction applied with result")?; + unauthorized_transfer.exp_string("Transaction is invalid")?; + unauthorized_transfer + .exp_string(&format!("Rejected: {established_addr}"))?; + unauthorized_transfer.assert_success(); + + let established_balance = helpers::fetch_red_token_balance( + &test, + &rpc_addr, + &multitoken_alias, + established_alias, + )?; + assert_eq!(established_balance, established_starting_red_balance); + + // attempt an authorized transfer to Albert from the established account + let mut authorized_transfer = helpers::attempt_red_tokens_transfer( + &test, + &rpc_addr, + &multitoken_alias, + established_alias, + BERTHA, + ALBERT_KEY, + &transfer_amount, + )?; + authorized_transfer.exp_string("Transaction applied with result")?; + authorized_transfer.exp_string("Transaction is valid")?; + authorized_transfer.assert_success(); + + let established_balance = helpers::fetch_red_token_balance( + &test, + &rpc_addr, + &multitoken_alias, + established_alias, + )?; + assert_eq!( + established_balance, + established_starting_red_balance - transfer_amount + ); + + Ok(()) +} + +#[test] +fn test_multitoken_transfer_implicit_to_established() -> Result<()> { + let (test, _ledger) = e2e::helpers::setup_single_node_test()?; + + let rpc_addr = get_actor_rpc(&test, &Who::Validator(0)); + let multitoken_alias = helpers::init_multitoken_vp(&test, &rpc_addr)?; + + let multitoken_vp_addr = + e2e::helpers::find_address(&test, &multitoken_alias)?; + println!("Fake multitoken VP established at {}", multitoken_vp_addr); + + // create an established account controlled by Bertha + let established_alias = "established"; + e2e::helpers::init_established_account( + &test, + &rpc_addr, + BERTHA, + BERTHA_KEY, + established_alias, + )?; + + let albert_addr = e2e::helpers::find_address(&test, ALBERT)?; + let albert_starting_red_balance = token::Amount::native_whole(100_000_000); + helpers::mint_red_tokens( + &test, + &rpc_addr, + &multitoken_vp_addr, + &albert_addr, + &albert_starting_red_balance, + )?; + + let transfer_amount = token::Amount::native_whole(10_000_000); + + // attempt an unauthorized transfer from Albert to the established account + let mut unauthorized_transfer = helpers::attempt_red_tokens_transfer( + &test, + &rpc_addr, + &multitoken_alias, + ALBERT, + established_alias, + CHRISTEL_KEY, + &transfer_amount, + )?; + unauthorized_transfer.exp_string("Transaction applied with result")?; + unauthorized_transfer.exp_string("Transaction is invalid")?; + unauthorized_transfer.exp_string(&format!("Rejected: {albert_addr}"))?; + unauthorized_transfer.assert_success(); + + let albert_balance = helpers::fetch_red_token_balance( + &test, + &rpc_addr, + &multitoken_alias, + ALBERT, + )?; + assert_eq!(albert_balance, albert_starting_red_balance); + + // attempt an authorized transfer to Albert from the established account + let mut authorized_transfer = helpers::attempt_red_tokens_transfer( + &test, + &rpc_addr, + &multitoken_alias, + ALBERT, + established_alias, + ALBERT_KEY, + &transfer_amount, + )?; + authorized_transfer.exp_string("Transaction applied with result")?; + authorized_transfer.exp_string("Transaction is valid")?; + authorized_transfer.assert_success(); + + let albert_balance = helpers::fetch_red_token_balance( + &test, + &rpc_addr, + &multitoken_alias, + ALBERT, + )?; + assert_eq!( + albert_balance, + albert_starting_red_balance - transfer_amount + ); + + Ok(()) +} + +#[test] +fn test_multitoken_transfer_established_to_established() -> Result<()> { + let (test, _ledger) = e2e::helpers::setup_single_node_test()?; + + let rpc_addr = get_actor_rpc(&test, &Who::Validator(0)); + let multitoken_alias = helpers::init_multitoken_vp(&test, &rpc_addr)?; + + let multitoken_vp_addr = + e2e::helpers::find_address(&test, &multitoken_alias)?; + println!("Fake multitoken VP established at {}", multitoken_vp_addr); + + // create an established account that Albert controls + let established_alias = "established"; + e2e::helpers::init_established_account( + &test, + &rpc_addr, + ALBERT, + ALBERT_KEY, + established_alias, + )?; + + let established_starting_red_balance = + token::Amount::native_whole(100_000_000); + // mint some red tokens for the established account + let established_addr = + e2e::helpers::find_address(&test, established_alias)?; + helpers::mint_red_tokens( + &test, + &rpc_addr, + &multitoken_vp_addr, + &established_addr, + &established_starting_red_balance, + )?; + + // create another established account to receive transfers + let receiver_alias = "receiver"; + e2e::helpers::init_established_account( + &test, + &rpc_addr, + BERTHA, + BERTHA_KEY, + receiver_alias, + )?; + + let established_starting_red_balance = + token::Amount::native_whole(100_000_000); + // mint some red tokens for the established account + let established_addr = + e2e::helpers::find_address(&test, established_alias)?; + helpers::mint_red_tokens( + &test, + &rpc_addr, + &multitoken_vp_addr, + &established_addr, + &established_starting_red_balance, + )?; + + let transfer_amount = token::Amount::native_whole(10_000_000); + + // attempt an unauthorized transfer + let mut unauthorized_transfer = helpers::attempt_red_tokens_transfer( + &test, + &rpc_addr, + &multitoken_alias, + established_alias, + receiver_alias, + CHRISTEL_KEY, + &transfer_amount, + )?; + unauthorized_transfer.exp_string("Transaction applied with result")?; + unauthorized_transfer.exp_string("Transaction is invalid")?; + unauthorized_transfer + .exp_string(&format!("Rejected: {established_addr}"))?; + unauthorized_transfer.assert_success(); + + let established_balance = helpers::fetch_red_token_balance( + &test, + &rpc_addr, + &multitoken_alias, + established_alias, + )?; + assert_eq!(established_balance, established_starting_red_balance); + + // attempt an authorized transfer which should succeed + let mut authorized_transfer = helpers::attempt_red_tokens_transfer( + &test, + &rpc_addr, + &multitoken_alias, + established_alias, + receiver_alias, + ALBERT_KEY, + &transfer_amount, + )?; + authorized_transfer.exp_string("Transaction applied with result")?; + authorized_transfer.exp_string("Transaction is valid")?; + authorized_transfer.assert_success(); + + let established_balance = helpers::fetch_red_token_balance( + &test, + &rpc_addr, + &multitoken_alias, + established_alias, + )?; + assert_eq!( + established_balance, + established_starting_red_balance - transfer_amount + ); + + Ok(()) +} diff --git a/tests/src/e2e/multitoken_tests/helpers.rs b/tests/src/e2e/multitoken_tests/helpers.rs new file mode 100644 index 0000000000..176692c508 --- /dev/null +++ b/tests/src/e2e/multitoken_tests/helpers.rs @@ -0,0 +1,190 @@ +//! Helpers for use in multitoken tests. +use std::path::PathBuf; + +use borsh::BorshSerialize; +use color_eyre::eyre::Result; +use eyre::Context; +use namada_core::types::address::Address; +use namada_core::types::token::NATIVE_MAX_DECIMAL_PLACES; +use namada_core::types::{storage, token}; +use namada_test_utils::tx_data::TxWriteData; +use namada_test_utils::TestWasms; +use namada_tx_prelude::storage::KeySeg; +use rand::Rng; +use regex::Regex; + +use super::setup::constants::NAM; +use super::setup::{Bin, NamadaCmd, Test}; +use crate::e2e::setup::constants::{ALBERT, ALBERT_KEY}; +use crate::run; + +const MULTITOKEN_KEY_SEGMENT: &str = "tokens"; +const BALANCE_KEY_SEGMENT: &str = "balance"; +const RED_TOKEN_KEY_SEGMENT: &str = "red"; +const MULTITOKEN_RED_TOKEN_SUB_PREFIX: &str = "tokens/red"; + +const ARBITRARY_SIGNER: &str = ALBERT; +const ARBITRARY_SIGNER_KEY: &str = ALBERT_KEY; + +/// Initializes a VP to represent a multitoken account. +pub fn init_multitoken_vp(test: &Test, rpc_addr: &str) -> Result { + // we use a VP that always returns true for the multitoken VP here, as we + // are testing out the VPs of the sender and receiver of multitoken + // transactions here - not any multitoken VP itself + let multitoken_vp_wasm_path = + TestWasms::VpAlwaysTrue.path().to_string_lossy().to_string(); + let multitoken_alias = "multitoken"; + + let init_account_args = vec![ + "init-account", + "--source", + ARBITRARY_SIGNER, + "--public-key", + // Value obtained from + // `namada::types::key::ed25519::tests::gen_keypair` + "001be519a321e29020fa3cbfbfd01bd5e92db134305609270b71dace25b5a21168", + "--code-path", + &multitoken_vp_wasm_path, + "--alias", + multitoken_alias, + "--gas-amount", + "0", + "--gas-limit", + "0", + "--gas-token", + NAM, + "--ledger-address", + rpc_addr, + ]; + let mut client_init_account = + run!(test, Bin::Client, init_account_args, Some(40))?; + client_init_account.exp_string("Transaction is valid.")?; + client_init_account.exp_string("Transaction applied")?; + client_init_account.assert_success(); + Ok(multitoken_alias.to_string()) +} + +/// Generates a random path within the `test` directory. +fn generate_random_test_dir_path(test: &Test) -> PathBuf { + let rng = rand::thread_rng(); + let random_string: String = rng + .sample_iter(&rand::distributions::Alphanumeric) + .take(24) + .map(char::from) + .collect(); + test.test_dir.path().join(random_string) +} + +/// Writes `contents` to a random path within the `test` directory, and return +/// the path. +pub fn write_test_file( + test: &Test, + contents: impl AsRef<[u8]>, +) -> Result { + let path = generate_random_test_dir_path(test); + std::fs::write(&path, contents)?; + Ok(path) +} + +/// Mint red tokens to the given address. +pub fn mint_red_tokens( + test: &Test, + rpc_addr: &str, + multitoken: &Address, + owner: &Address, + amount: &token::Amount, +) -> Result<()> { + let red_balance_key = storage::Key::from(multitoken.to_db_key()) + .push(&MULTITOKEN_KEY_SEGMENT.to_owned())? + .push(&RED_TOKEN_KEY_SEGMENT.to_owned())? + .push(&BALANCE_KEY_SEGMENT.to_owned())? + .push(owner)?; + + let tx_code_path = TestWasms::TxWriteStorageKey.path(); + let tx_data_path = write_test_file( + test, + TxWriteData { + key: red_balance_key, + value: amount.try_to_vec()?, + } + .try_to_vec()?, + )?; + + let tx_data_path = tx_data_path.to_string_lossy().to_string(); + let tx_code_path = tx_code_path.to_string_lossy().to_string(); + let tx_args = vec![ + "tx", + "--signing-keys", + ARBITRARY_SIGNER_KEY, + "--code-path", + &tx_code_path, + "--data-path", + &tx_data_path, + "--ledger-address", + rpc_addr, + ]; + let mut client_tx = run!(test, Bin::Client, tx_args, Some(40))?; + client_tx.exp_string("Transaction is valid.")?; + client_tx.exp_string("Transaction applied")?; + client_tx.assert_success(); + Ok(()) +} + +pub fn attempt_red_tokens_transfer( + test: &Test, + rpc_addr: &str, + multitoken: &str, + from: &str, + to: &str, + signing_keys: &str, + amount: &token::Amount, +) -> Result { + let amount = amount.to_string_native(); + let transfer_args = vec![ + "transfer", + "--token", + multitoken, + "--sub-prefix", + MULTITOKEN_RED_TOKEN_SUB_PREFIX, + "--source", + from, + "--target", + to, + "--signing-keys", + signing_keys, + "--amount", + &amount, + "--ledger-address", + rpc_addr, + ]; + run!(test, Bin::Client, transfer_args, Some(40)) +} + +pub fn fetch_red_token_balance( + test: &Test, + rpc_addr: &str, + multitoken_alias: &str, + owner_alias: &str, +) -> Result { + let balance_args = vec![ + "balance", + "--owner", + owner_alias, + "--token", + multitoken_alias, + "--sub-prefix", + MULTITOKEN_RED_TOKEN_SUB_PREFIX, + "--ledger-address", + rpc_addr, + ]; + let mut client_balance = run!(test, Bin::Client, balance_args, Some(40))?; + let (_, matched) = client_balance.exp_regex(&format!( + r"{MULTITOKEN_RED_TOKEN_SUB_PREFIX}: (\d*\.?\d+)" + ))?; + let decimal_regex = Regex::new(r"(\d*\.?\d+)").unwrap(); + println!("Got balance for {}: {}", owner_alias, matched); + let decimal = decimal_regex.find(&matched).unwrap().as_str(); + client_balance.assert_success(); + token::Amount::from_str(decimal, NATIVE_MAX_DECIMAL_PLACES) + .wrap_err(format!("Failed to parse {}", matched)) +} diff --git a/tests/src/e2e/setup.rs b/tests/src/e2e/setup.rs index 5f148b4fc2..eecc60588f 100644 --- a/tests/src/e2e/setup.rs +++ b/tests/src/e2e/setup.rs @@ -839,6 +839,7 @@ pub mod constants { pub const CHRISTEL: &str = "Christel"; pub const CHRISTEL_KEY: &str = "Christel-key"; pub const DAEWON: &str = "Daewon"; + pub const DAEWON_KEY: &str = "Daewon-key"; pub const ESTER: &str = "Ester"; pub const MATCHMAKER_KEY: &str = "matchmaker-key"; pub const MASP: &str = "atest1v4ehgw36xaryysfsx5unvve4g5my2vjz89p52sjxxgenzd348yuyyv3hg3pnjs35g5unvde4ca36y5"; diff --git a/tests/src/integration/masp.rs b/tests/src/integration/masp.rs index b8f9c47ed5..d024f84132 100644 --- a/tests/src/integration/masp.rs +++ b/tests/src/integration/masp.rs @@ -391,7 +391,7 @@ fn masp_incentives() -> Result<()> { ETH, "--amount", "10", - "--signer", + "--signing-keys", BERTHA, "--node", validator_one_rpc, @@ -488,7 +488,7 @@ fn masp_incentives() -> Result<()> { BTC, "--amount", "20", - "--signer", + "--signing-keys", ALBERT, "--node", validator_one_rpc, @@ -661,7 +661,7 @@ fn masp_incentives() -> Result<()> { "--amount", &((amt10 * masp_rewards[ð()]).0 * (ep5.0 - ep3.0)) .to_string_native(), - "--signer", + "--signing-keys", BERTHA, "--node", validator_one_rpc, @@ -687,7 +687,7 @@ fn masp_incentives() -> Result<()> { "--amount", &((amt20 * masp_rewards[&btc()]).0 * (ep6.0 - ep0.0)) .to_string_native(), - "--signer", + "--signing-keys", ALBERT, "--node", validator_one_rpc, diff --git a/tests/src/native_vp/eth_bridge_pool.rs b/tests/src/native_vp/eth_bridge_pool.rs index 46478acf48..544889b2d1 100644 --- a/tests/src/native_vp/eth_bridge_pool.rs +++ b/tests/src/native_vp/eth_bridge_pool.rs @@ -8,7 +8,7 @@ mod test_bridge_pool_vp { wrapped_erc20s, Contracts, EthereumBridgeConfig, UpgradeableContract, }; 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::{ @@ -17,7 +17,6 @@ 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_apps::wallet::defaults::{albert_address, bertha_address}; use namada_apps::wasm_loader; @@ -108,14 +107,11 @@ 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, - ))); + + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(wasm_code) + .add_serialized_data(data) + .sign_wrapper(keypair.clone()); tx } diff --git a/tests/src/native_vp/pos.rs b/tests/src/native_vp/pos.rs index b76b4dd041..077385dc61 100644 --- a/tests/src/native_vp/pos.rs +++ b/tests/src/native_vp/pos.rs @@ -118,6 +118,11 @@ pub fn init_pos( tx_env.spawn_accounts([&native_token]); for validator in genesis_validators { tx_env.spawn_accounts([&validator.address]); + tx_env.init_account_storage( + &validator.address, + vec![validator.consensus_key.clone()], + 1, + ) } tx_env.wl_storage.storage.block.epoch = start_epoch; // Initialize PoS storage diff --git a/tests/src/vm_host_env/ibc.rs b/tests/src/vm_host_env/ibc.rs index 5858abe7d3..f88be446fe 100644 --- a/tests/src/vm_host_env/ibc.rs +++ b/tests/src/vm_host_env/ibc.rs @@ -1,6 +1,5 @@ use core::time::Duration; use std::collections::HashMap; -use std::str::FromStr; use namada::ibc::applications::transfer::acknowledgement::TokenTransferAcknowledgement; use namada::ibc::applications::transfer::coin::PrefixedCoin; @@ -24,16 +23,11 @@ use namada::ibc::core::ics03_connection::version::Version as ConnVersion; use namada::ibc::core::ics04_channel::channel::{ ChannelEnd, Counterparty as ChanCounterparty, Order, State as ChanState, }; -use namada::ibc::core::ics04_channel::msgs::acknowledgement::MsgAcknowledgement; -use namada::ibc::core::ics04_channel::msgs::chan_close_confirm::MsgChannelCloseConfirm; -use namada::ibc::core::ics04_channel::msgs::chan_close_init::MsgChannelCloseInit; -use namada::ibc::core::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; -use namada::ibc::core::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; -use namada::ibc::core::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; -use namada::ibc::core::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; -use namada::ibc::core::ics04_channel::msgs::recv_packet::MsgRecvPacket; -use namada::ibc::core::ics04_channel::msgs::timeout::MsgTimeout; -use namada::ibc::core::ics04_channel::msgs::timeout_on_close::MsgTimeoutOnClose; +use namada::ibc::core::ics04_channel::msgs::{ + MsgAcknowledgement, MsgChannelCloseConfirm, MsgChannelCloseInit, + MsgChannelOpenAck, MsgChannelOpenConfirm, MsgChannelOpenInit, + MsgChannelOpenTry, MsgRecvPacket, MsgTimeout, MsgTimeoutOnClose, +}; pub use namada::ibc::core::ics04_channel::packet::{Packet, Sequence}; use namada::ibc::core::ics04_channel::timeout::TimeoutHeight; use namada::ibc::core::ics04_channel::Version as ChanVersion; @@ -41,15 +35,13 @@ use namada::ibc::core::ics23_commitment::commitment::{ CommitmentPrefix, CommitmentProofBytes, }; pub use namada::ibc::core::ics24_host::identifier::{ - ChannelId, ClientId, ConnectionId, PortChannelId, PortId, + ChannelId, ClientId, ConnectionId, PortId, }; +use namada::ibc::core::timestamp::Timestamp; use namada::ibc::mock::client_state::{MockClientState, MOCK_CLIENT_TYPE}; use namada::ibc::mock::consensus_state::MockConsensusState; use namada::ibc::mock::header::MockHeader; -use namada::ibc::signer::Signer; -use namada::ibc::timestamp::Timestamp; use namada::ibc::Height; -use namada::ibc_proto::cosmos::base::v1beta1::Coin; use namada::ibc_proto::google::protobuf::Any; use namada::ibc_proto::ibc::core::commitment::v1::MerkleProof; use namada::ibc_proto::ibc::core::connection::v1::MsgConnectionOpenTry as RawMsgConnectionOpenTry; @@ -58,9 +50,9 @@ use namada::ibc_proto::protobuf::Protobuf; use namada::ledger::gas::VpGasMeter; pub use namada::ledger::ibc::storage::{ ack_key, channel_counter_key, channel_key, client_counter_key, - client_state_key, client_type_key, client_update_height_key, - client_update_timestamp_key, commitment_key, connection_counter_key, - connection_key, consensus_state_key, ibc_token, next_sequence_ack_key, + client_state_key, client_update_height_key, client_update_timestamp_key, + commitment_key, connection_counter_key, connection_key, + consensus_state_key, ibc_token, next_sequence_ack_key, next_sequence_recv_key, next_sequence_send_key, port_key, receipt_key, }; use namada::ledger::ibc::vp::{ @@ -296,23 +288,12 @@ pub fn prepare_client() -> (ClientId, Any, HashMap>) { // client state let client_id = client_id(); let key = client_state_key(&client_id); - let bytes = client_state - .into_box() - .encode_vec() - .expect("encoding failed"); - writes.insert(key, bytes); - // client type - let key = client_type_key(&client_id); - let client_type = client_state.client_type(); - let bytes = client_type.as_str().as_bytes().to_vec(); + let bytes = client_state.into_box().encode_vec(); writes.insert(key, bytes); // consensus state let height = client_state.latest_height(); let key = consensus_state_key(&client_id, height); - let bytes = consensus_state - .into_box() - .encode_vec() - .expect("encoding failed"); + let bytes = consensus_state.into_box().encode_vec(); writes.insert(key, bytes); // client update time let key = client_update_timestamp_key(&client_id); @@ -337,7 +318,7 @@ pub fn prepare_client() -> (ClientId, Any, HashMap>) { let height = env.wl_storage.storage.get_block_height().0; Height::new(0, height.0).expect("invalid height") }); - let bytes = height.encode_vec().expect("encoding failed"); + let bytes = height.encode_vec(); writes.insert(key, bytes); // client counter let key = client_counter_key(); @@ -366,15 +347,15 @@ pub fn prepare_opened_connection( let conn_id = ConnectionId::new(0); let key = connection_key(&conn_id); - let msg = msg_connection_open_init(client_id.clone()); let conn = ConnectionEnd::new( ConnState::Open, - msg.client_id_on_a.clone(), - msg.counterparty.clone(), - vec![msg.version.clone().unwrap_or_default()], - msg.delay_period, - ); - let bytes = conn.encode_vec().expect("encoding failed"); + client_id.clone(), + dummy_connection_counterparty(), + vec![ConnVersion::default()], + Duration::new(0, 0), + ) + .expect("invalid connection"); + let bytes = conn.encode_vec(); writes.insert(key, bytes); // connection counter let key = connection_counter_key(); @@ -396,20 +377,19 @@ pub fn prepare_opened_channel( writes.insert(key, 0_u64.to_be_bytes().to_vec()); // channel let channel_id = ChannelId::new(0); - let port_channel_id = - PortChannelId::new(channel_id.clone(), port_id.clone()); - let key = channel_key(&port_channel_id); + let key = channel_key(&port_id, &channel_id); let mut channel = ChannelEnd::new( ChanState::Open, Order::Unordered, dummy_channel_counterparty(), vec![conn_id.clone()], ChanVersion::new(VERSION.to_string()), - ); + ) + .expect("invalid channel"); if is_ordered { channel.ordering = Order::Ordered; } - let bytes = channel.encode_vec().expect("encoding failed"); + let bytes = channel.encode_vec(); writes.insert(key, bytes); (port_id, channel_id, writes) @@ -420,7 +400,7 @@ pub fn msg_create_client() -> MsgCreateClient { MsgCreateClient { client_state: client_state.into(), consensus_state: consensus_state.into(), - signer: Signer::from_str("test").expect("invalid signer"), + signer: "test".to_string().into(), } } @@ -434,7 +414,7 @@ pub fn msg_update_client(client_id: ClientId) -> MsgUpdateClient { MsgUpdateClient { client_id, header, - signer: Signer::from_str("test").expect("invalid signer"), + signer: "test".to_string().into(), } } @@ -458,17 +438,24 @@ pub fn msg_upgrade_client(client_id: ClientId) -> MsgUpgradeClient { consensus_state, proof_upgrade_client, proof_upgrade_consensus_state, - signer: Signer::from_str("test").expect("invalid signer"), + signer: "test".to_string().into(), } } pub fn msg_connection_open_init(client_id: ClientId) -> MsgConnectionOpenInit { + let client_type = ClientType::new(MOCK_CLIENT_TYPE.to_string()).unwrap(); + let counterparty_client_id = ClientId::new(client_type, 42).unwrap(); + let commitment_prefix = + CommitmentPrefix::try_from(COMMITMENT_PREFIX.to_vec()).unwrap(); + let counterparty = + ConnCounterparty::new(counterparty_client_id, None, commitment_prefix); + MsgConnectionOpenInit { client_id_on_a: client_id, - counterparty: dummy_connection_counterparty(), + counterparty, version: None, delay_period: Duration::new(0, 0), - signer: Signer::from_str("test").expect("invalid signer"), + signer: "test".to_string().into(), } } @@ -514,7 +501,7 @@ pub fn msg_connection_open_ack( proofs_height_on_b: dummy_proof_height(), consensus_height_of_a_on_b: consensus_height, version: ConnVersion::default(), - signer: Signer::from_str("test").expect("invalid signer"), + signer: "test".to_string().into(), } } @@ -525,7 +512,7 @@ pub fn msg_connection_open_confirm( conn_id_on_b: connection_id, proof_conn_end_on_a: dummy_proof(), proof_height_on_a: dummy_proof_height(), - signer: Signer::from_str("test").expect("invalid signer"), + signer: "test".to_string().into(), } } @@ -538,7 +525,7 @@ fn dummy_proof_height() -> Height { } fn dummy_connection_counterparty() -> ConnCounterparty { - let client_type = ClientType::new(MOCK_CLIENT_TYPE.to_string()); + let client_type = ClientType::new(MOCK_CLIENT_TYPE.to_string()).unwrap(); let client_id = ClientId::new(client_type, 42).expect("invalid client ID"); let conn_id = ConnectionId::new(12); let commitment_prefix = @@ -556,7 +543,7 @@ pub fn msg_channel_open_init( connection_hops_on_a: vec![conn_id], port_id_on_b: PortId::transfer(), ordering: Order::Unordered, - signer: Signer::from_str("test").expect("invalid signer"), + signer: "test".to_string().into(), version_proposal: ChanVersion::new(VERSION.to_string()), } } @@ -576,8 +563,7 @@ pub fn msg_channel_open_try( proof_chan_end_on_a: dummy_proof(), proof_height_on_a: dummy_proof_height(), ordering: Order::Unordered, - signer: Signer::from_str("test").expect("invalid signer"), - previous_channel_id: ChannelId::default().to_string(), + signer: "test".to_string().into(), version_proposal: ChanVersion::default(), } } @@ -594,7 +580,7 @@ pub fn msg_channel_open_ack( version_on_b: ChanVersion::new(VERSION.to_string()), proof_chan_end_on_b: dummy_proof(), proof_height_on_b: dummy_proof_height(), - signer: Signer::from_str("test").expect("invalid signer"), + signer: "test".to_string().into(), } } @@ -607,7 +593,7 @@ pub fn msg_channel_open_confirm( chan_id_on_b: channel_id, proof_chan_end_on_a: dummy_proof(), proof_height_on_a: dummy_proof_height(), - signer: Signer::from_str("test").expect("invalid signer"), + signer: "test".to_string().into(), } } @@ -618,7 +604,7 @@ pub fn msg_channel_close_init( MsgChannelCloseInit { port_id_on_a: port_id, chan_id_on_a: channel_id, - signer: Signer::from_str("test").expect("invalid signer"), + signer: "test".to_string().into(), } } @@ -631,7 +617,7 @@ pub fn msg_channel_close_confirm( chan_id_on_b: channel_id, proof_chan_end_on_a: dummy_proof(), proof_height_on_a: dummy_proof_height(), - signer: Signer::from_str("test").expect("invalid signer"), + signer: "test".to_string().into(), } } @@ -648,22 +634,24 @@ pub fn unorder_channel(channel: &mut ChannelEnd) { pub fn msg_transfer( port_id: PortId, channel_id: ChannelId, - token: String, + denom: String, sender: &Address, ) -> MsgTransfer { let timestamp = (Timestamp::now() + Duration::from_secs(100)).unwrap(); MsgTransfer { port_id_on_a: port_id, chan_id_on_a: channel_id, - token: Coin { - denom: token, - amount: 100u64.to_string(), + packet_data: PacketData { + token: PrefixedCoin { + denom: denom.parse().expect("invalid denom"), + amount: 100.into(), + }, + sender: sender.to_string().into(), + receiver: address::testing::gen_established_address() + .to_string() + .into(), + memo: "memo".to_string().into(), }, - sender: Signer::from_str(&sender.to_string()).expect("invalid signer"), - receiver: Signer::from_str( - &address::testing::gen_established_address().to_string(), - ) - .expect("invalid signer"), timeout_height_on_b: TimeoutHeight::Never, timeout_timestamp_on_b: timestamp, } @@ -679,7 +667,7 @@ pub fn msg_packet_recv(packet: Packet) -> MsgRecvPacket { packet, proof_commitment_on_a: dummy_proof(), proof_height_on_a: dummy_proof_height(), - signer: Signer::from_str("test").expect("invalid signer"), + signer: "test".to_string().into(), } } @@ -690,7 +678,7 @@ pub fn msg_packet_ack(packet: Packet) -> MsgAcknowledgement { acknowledgement: packet_ack.into(), proof_acked_on_b: dummy_proof(), proof_height_on_b: dummy_proof_height(), - signer: Signer::from_str("test").expect("invalid signer"), + signer: "test".to_string().into(), } } @@ -707,12 +695,12 @@ pub fn received_packet( denom: token.parse().expect("invalid denom"), amount: 100.into(), }; - let sender = address::testing::gen_established_address().to_string(); + let sender = address::testing::gen_established_address(); let data = PacketData { token: coin, - sender: Signer::from_str(&sender).expect("invalid signer"), - receiver: Signer::from_str(&receiver.to_string()) - .expect("invalid signer"), + sender: sender.to_string().into(), + receiver: receiver.to_string().into(), + memo: "memo".to_string().into(), }; Packet { seq_on_a: sequence, @@ -732,7 +720,7 @@ pub fn msg_timeout(packet: Packet, next_sequence_recv: Sequence) -> MsgTimeout { next_seq_recv_on_b: next_sequence_recv, proof_unreceived_on_b: dummy_proof(), proof_height_on_b: dummy_proof_height(), - signer: Signer::from_str("test").expect("invalid signer"), + signer: "test".to_string().into(), } } @@ -746,7 +734,7 @@ pub fn msg_timeout_on_close( proof_unreceived_on_b: dummy_proof(), proof_close_on_b: dummy_proof(), proof_height_on_b: dummy_proof_height(), - signer: Signer::from_str("test").expect("invalid signer"), + signer: "test".to_string().into(), } } @@ -755,11 +743,11 @@ pub fn packet_from_message( sequence: Sequence, counterparty: &ChanCounterparty, ) -> Packet { - let coin = PrefixedCoin::try_from(msg.token.clone()).expect("invalid coin"); let packet_data = PacketData { - token: coin, - sender: msg.sender.clone(), - receiver: msg.receiver.clone(), + token: msg.packet_data.token.clone(), + sender: msg.packet_data.sender.clone(), + receiver: msg.packet_data.receiver.clone(), + memo: "memo".to_string().into(), }; let data = serde_json::to_vec(&packet_data).expect("Encoding PacketData failed"); diff --git a/tests/src/vm_host_env/mod.rs b/tests/src/vm_host_env/mod.rs index a8c72cf9b7..878d93aeef 100644 --- a/tests/src/vm_host_env/mod.rs +++ b/tests/src/vm_host_env/mod.rs @@ -21,25 +21,28 @@ mod tests { use std::panic; use itertools::Itertools; - use namada::ibc::tx_msg::Msg; + use namada::ibc::core::Msg; use namada::ledger::ibc::storage as ibc_storage; use namada::ledger::ibc::vp::{ get_dummy_header as tm_dummy_header, Error as IbcError, }; use namada::ledger::tx_env::TxEnv; - use namada::proto::{Code, Data, Section, Signature, Tx}; - use namada::types::address::{Address, InternalAddress}; + use namada::proto::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::{address, key}; use namada_core::ledger::ibc::context::transfer_mod::testing::DummyTransferModule; use namada_core::ledger::ibc::Error as IbcActionError; use namada_test_utils::TestWasms; - use namada_tx_prelude::{BorshSerialize, StorageRead, StorageWrite}; + use namada_tx_prelude::address::InternalAddress; + use namada_tx_prelude::chain::ChainId; + use namada_tx_prelude::{ + Address, BorshSerialize, StorageRead, StorageWrite, + }; + use namada_vp_prelude::account::AccountPublicKeysMap; use namada_vp_prelude::VpEnv; use prost::Message; use test_log::test; @@ -437,12 +440,11 @@ mod tests { let addr = address::testing::established_address_1(); // Write the public key to storage - let pk_key = key::pk_key(&addr); let keypair = key::testing::keypair_1(); let pk = keypair.ref_to(); - env.wl_storage - .write(&pk_key, pk.try_to_vec().unwrap()) - .unwrap(); + + let _ = pks_handle(&addr).insert(&mut env.wl_storage, 0_u8, pk.clone()); + // Initialize the environment vp_host_env::set(env); @@ -455,28 +457,29 @@ mod tests { // Tx without any data vec![], ] { + 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &keypair, - ))); + let chain_id = env.wl_storage.storage.chain_id.clone(); + let mut tx = Tx::new(chain_id, expiration); + tx.add_code(code.clone()) + .add_serialized_data(data.to_vec()) + .sign_raw(keypairs.clone(), pks_map.clone()) + .sign_wrapper(keypair.clone()); env.tx = tx; env.tx.clone() }); assert_eq!(signed_tx_data.data().as_ref(), Some(data)); assert!( signed_tx_data - .verify_signature( - &pk, + .verify_section_signatures( &[ *signed_tx_data.data_sechash(), *signed_tx_data.code_sechash(), ], + pks_map, + 1, + None ) .is_ok() ); @@ -484,12 +487,16 @@ mod tests { let other_keypair = key::testing::keypair_2(); assert!( signed_tx_data - .verify_signature( - &other_keypair.ref_to(), + .verify_section_signatures( &[ *signed_tx_data.data_sechash(), *signed_tx_data.code_sechash(), ], + AccountPublicKeysMap::from_iter([ + other_keypair.ref_to() + ]), + 1, + None ) .is_err() ); @@ -543,13 +550,17 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let keypair = key::testing::keypair_1(); + let keypairs = vec![keypair.clone()]; + let pks_map = AccountPublicKeysMap::from_iter([ + key::testing::keypair_1().ref_to(), + ]); + + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(input_data.clone()) + .sign_raw(keypairs.clone(), pks_map.clone()) + .sign_wrapper(keypair.clone()); let result = vp::CTX.eval(empty_code, tx).unwrap(); assert!(!result); @@ -561,14 +572,11 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code_from_hash(code_hash) + .add_serialized_data(input_data.clone()) + .sign_raw(keypairs.clone(), pks_map.clone()) + .sign_wrapper(keypair.clone()); let result = vp::CTX.eval(code_hash, tx).unwrap(); assert!(result); @@ -581,14 +589,11 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code_from_hash(code_hash) + .add_serialized_data(input_data) + .sign_raw(keypairs, pks_map) + .sign_wrapper(keypair); let result = vp::CTX.eval(code_hash, tx).unwrap(); assert!(!result); } @@ -599,18 +604,21 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs.clone(), pks_map.clone()) + .sign_wrapper(keypair.clone()); // create a client with the message tx_host_env::ibc::ibc_actions(tx::ctx()) @@ -640,13 +648,11 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs, pks_map) + .sign_wrapper(keypair); // update the client with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -663,6 +669,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(); @@ -679,13 +691,11 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs.clone(), pks_map.clone()) + .sign_wrapper(keypair.clone()); // init a connection with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -714,13 +724,11 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs, pks_map) + .sign_wrapper(keypair); // open the connection with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -740,6 +748,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| { @@ -754,13 +768,11 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs.clone(), pks_map.clone()) + .sign_wrapper(keypair.clone()); // open try a connection with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -789,13 +801,11 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs, pks_map) + .sign_wrapper(keypair); // open the connection with the mssage tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -812,6 +822,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(); @@ -831,13 +847,11 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs.clone(), pks_map.clone()) + .sign_wrapper(keypair.clone()); // init a channel with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -866,13 +880,11 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs, pks_map) + .sign_wrapper(keypair); // open the channle with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -903,18 +915,22 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs.clone(), pks_map.clone()) + .sign_wrapper(keypair.clone()); // try open a channel with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -944,13 +960,11 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs, pks_map) + .sign_wrapper(keypair); // open a channel with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -984,18 +998,22 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs, pks_map) + .sign_wrapper(keypair); // close the channel with the message let mut actions = tx_host_env::ibc::ibc_actions(tx::ctx()); // the dummy module closes the channel @@ -1037,18 +1055,22 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs, pks_map) + .sign_wrapper(keypair); // close the channel with the message tx_host_env::ibc::ibc_actions(tx::ctx()) @@ -1083,6 +1105,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); @@ -1092,13 +1120,11 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs.clone(), pks_map.clone()) + .sign_wrapper(keypair.clone()); // send the token and a packet with the data tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -1141,13 +1167,11 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs, pks_map) + .sign_wrapper(keypair); // ack the packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -1179,6 +1203,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(); @@ -1217,18 +1247,15 @@ mod tests { // Start a transaction to send a packet // Set this chain is the sink zone - let hashed_denom = ibc_token.to_string(); - let msg = ibc::msg_transfer(port_id, channel_id, hashed_denom, &sender); + let msg = ibc::msg_transfer(port_id, channel_id, denom, &sender); 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs, pks_map) + .sign_wrapper(keypair); // send the token and a packet with the data tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -1259,6 +1286,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(); @@ -1291,13 +1324,11 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs, pks_map) + .sign_wrapper(keypair); // receive a packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -1332,6 +1363,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(); @@ -1382,13 +1419,11 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs, pks_map) + .sign_wrapper(keypair); // receive a packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -1420,6 +1455,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(); @@ -1477,13 +1518,11 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs, pks_map) + .sign_wrapper(keypair); // receive a packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) .execute(&tx_data) @@ -1518,6 +1557,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(); @@ -1573,13 +1618,11 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs, pks_map) + .sign_wrapper(keypair); // timeout the packet tx_host_env::ibc::ibc_actions(tx::ctx()) @@ -1604,6 +1647,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(); @@ -1658,13 +1707,11 @@ 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::Signature(Signature::new( - vec![*tx.code_sechash(), *tx.data_sechash()], - &key::testing::keypair_1(), - ))); + let mut tx = Tx::new(ChainId::default(), None); + tx.add_code(vec![]) + .add_serialized_data(tx_data.clone()) + .sign_raw(keypairs, pks_map) + .sign_wrapper(keypair); // timeout the packet tx_host_env::ibc::ibc_actions(tx::ctx()) diff --git a/tests/src/vm_host_env/tx.rs b/tests/src/vm_host_env/tx.rs index d3da806ca5..a0e88ab802 100644 --- a/tests/src/vm_host_env/tx.rs +++ b/tests/src/vm_host_env/tx.rs @@ -18,7 +18,8 @@ use namada::vm::prefix_iter::PrefixIterators; use namada::vm::wasm::run::Error; use namada::vm::wasm::{self, TxCache, VpCache}; use namada::vm::{self, WasmCacheRwAccess}; -use namada_tx_prelude::{BorshSerialize, Ctx}; +use namada_tx_prelude::{storage_api, BorshSerialize, Ctx}; +use namada_vp_prelude::key::common; use tempfile::TempDir; use crate::vp::TestVpEnv; @@ -67,7 +68,7 @@ impl Default for TestTxEnv { storage: TestStorage::default(), write_log: WriteLog::default(), }; - let mut tx = Tx::new(TxType::Raw); + let mut tx = Tx::from_type(TxType::Raw); tx.header.chain_id = wl_storage.storage.chain_id.clone(); Self { wl_storage, @@ -102,6 +103,7 @@ impl TestTxEnv { epoch_duration: Option, vp_whitelist: Option>, tx_whitelist: Option>, + max_signatures_per_transaction: Option, ) { parameters::update_epoch_parameter( &mut self.wl_storage, @@ -121,6 +123,11 @@ impl TestTxEnv { vp_whitelist.unwrap_or_default(), ) .unwrap(); + parameters::update_max_signature_per_tx( + &mut self.wl_storage, + max_signatures_per_transaction.unwrap_or(15), + ) + .unwrap(); } pub fn store_wasm_code(&mut self, code: Vec) { @@ -155,6 +162,34 @@ impl TestTxEnv { } } + pub fn init_account_storage( + &mut self, + owner: &Address, + public_keys: Vec, + threshold: u8, + ) { + storage_api::account::init_account_storage( + &mut self.wl_storage, + owner, + &public_keys, + threshold, + ) + .expect("Unable to write Account substorage."); + } + + /// Set public key for the address. + pub fn write_account_threshold( + &mut self, + address: &Address, + threshold: u8, + ) { + let storage_key = key::threshold_key(address); + self.wl_storage + .storage + .write(&storage_key, threshold.try_to_vec().unwrap()) + .unwrap(); + } + /// Commit the genesis state. Typically, you'll want to call this after /// setting up the initial state, before running a transaction. pub fn commit_genesis(&mut self) { @@ -186,19 +221,6 @@ impl TestTxEnv { .unwrap(); } - /// Set public key for the address. - pub fn write_public_key( - &mut self, - address: &Address, - public_key: &key::common::PublicKey, - ) { - let storage_key = key::pk_key(address); - self.wl_storage - .storage - .write(&storage_key, public_key.try_to_vec().unwrap()) - .unwrap(); - } - /// Apply the tx changes to the write log. pub fn execute_tx(&mut self) -> Result<(), Error> { wasm::run::tx( diff --git a/tests/src/vm_host_env/vp.rs b/tests/src/vm_host_env/vp.rs index 02561dbc9a..890d0681d8 100644 --- a/tests/src/vm_host_env/vp.rs +++ b/tests/src/vm_host_env/vp.rs @@ -69,7 +69,7 @@ impl Default for TestVpEnv { storage: TestStorage::default(), write_log: WriteLog::default(), }; - let mut tx = Tx::new(TxType::Raw); + let mut tx = Tx::from_type(TxType::Raw); tx.header.chain_id = wl_storage.storage.chain_id.clone(); Self { addr: address::testing::established_address_1(), diff --git a/tx_prelude/src/account.rs b/tx_prelude/src/account.rs new file mode 100644 index 0000000000..da6c213601 --- /dev/null +++ b/tx_prelude/src/account.rs @@ -0,0 +1,18 @@ +use namada_core::types::transaction::account::InitAccount; + +use super::*; + +pub fn init_account( + ctx: &mut Ctx, + owner: &Address, + data: InitAccount, +) -> EnvResult
{ + storage_api::account::init_account_storage( + ctx, + owner, + &data.public_keys, + data.threshold, + )?; + + Ok(owner.to_owned()) +} diff --git a/tx_prelude/src/lib.rs b/tx_prelude/src/lib.rs index 6e5a0192c8..cd2f5d5f92 100644 --- a/tx_prelude/src/lib.rs +++ b/tx_prelude/src/lib.rs @@ -6,6 +6,7 @@ #![deny(rustdoc::broken_intra_doc_links)] #![deny(rustdoc::private_intra_doc_links)] +pub mod account; pub mod ibc; pub mod key; pub mod proof_of_stake; @@ -18,7 +19,6 @@ pub use borsh::{BorshDeserialize, BorshSerialize}; pub use namada_core::ledger::eth_bridge; pub use namada_core::ledger::governance::storage as gov_storage; pub use namada_core::ledger::parameters::storage as parameters_storage; -pub use namada_core::ledger::slash_fund::storage as slash_fund_storage; pub use namada_core::ledger::storage::types::encode; pub use namada_core::ledger::storage_api::{ self, governance, iter_prefix, iter_prefix_bytes, Error, OptionExt, diff --git a/tx_prelude/src/proof_of_stake.rs b/tx_prelude/src/proof_of_stake.rs index 48b0cb665f..cc8bcb7b63 100644 --- a/tx_prelude/src/proof_of_stake.rs +++ b/tx_prelude/src/proof_of_stake.rs @@ -2,7 +2,7 @@ use namada_core::types::dec::Dec; use namada_core::types::hash::Hash; -use namada_core::types::transaction::InitValidator; +use namada_core::types::transaction::pos::InitValidator; use namada_core::types::{key, token}; pub use namada_proof_of_stake::parameters::PosParams; use namada_proof_of_stake::{ @@ -74,7 +74,8 @@ impl Ctx { pub fn init_validator( &mut self, InitValidator { - account_key, + account_keys, + threshold, consensus_key, eth_cold_key, eth_hot_key, @@ -89,8 +90,12 @@ impl Ctx { let current_epoch = self.get_block_epoch()?; // Init validator account let validator_address = self.init_account(validator_vp_code_hash)?; - let pk_key = key::pk_key(&validator_address); - self.write(&pk_key, &account_key)?; + storage_api::account::init_account_storage( + self, + &validator_address, + &account_keys, + threshold, + )?; let protocol_pk_key = key::protocol_pk_key(&validator_address); self.write(&protocol_pk_key, &protocol_key)?; let dkg_pk_key = key::dkg_session_keys::dkg_pk_key(&validator_address); diff --git a/vp_prelude/src/lib.rs b/vp_prelude/src/lib.rs index 8ec55ef7cd..c8e555a87b 100644 --- a/vp_prelude/src/lib.rs +++ b/vp_prelude/src/lib.rs @@ -6,8 +6,6 @@ #![deny(rustdoc::broken_intra_doc_links)] #![deny(rustdoc::private_intra_doc_links)] -pub mod key; - // used in the VP input use core::convert::AsRef; use core::slice; @@ -74,11 +72,32 @@ pub fn log_string>(msg: T) { /// Checks if a proposal id is being executed pub fn is_proposal_accepted(ctx: &Ctx, proposal_id: u64) -> VpResult { let proposal_execution_key = - gov_storage::get_proposal_execution_key(proposal_id); + gov_storage::keys::get_proposal_execution_key(proposal_id); ctx.has_key_pre(&proposal_execution_key) } +/// Verify section signatures +pub fn verify_signatures(ctx: &Ctx, tx: &Tx, owner: &Address) -> VpResult { + let max_signatures_per_transaction = + parameters::max_signatures_per_transaction(&ctx.pre())?; + + let public_keys_index_map = + storage_api::account::public_keys_index_map(&ctx.pre(), owner)?; + let threshold = + storage_api::account::threshold(&ctx.pre(), owner)?.unwrap_or(1); + + let targets = &[*tx.data_sechash(), *tx.code_sechash()]; + tx.verify_section_signatures( + targets, + public_keys_index_map, + threshold, + max_signatures_per_transaction, + ) + .map_err(|_e| Error::SimpleMessage("Invalid signatures")) + .map(|_| true) +} + /// Checks whether a transaction is valid, which happens in two cases: /// - tx is whitelisted, or /// - tx is executed by an approved governance proposal (no need to be diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index a413f7b2fb..be65562b6d 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -278,28 +278,6 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" -[[package]] -name = "async-stream" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.16", -] - [[package]] name = "async-trait" version = "0.1.68" @@ -311,22 +289,6 @@ dependencies = [ "syn 2.0.16", ] -[[package]] -name = "async-tungstenite" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e00550829ef8e2c4115250d0ee43305649b0fa95f78a32ce5b07da0b73d95c5c" -dependencies = [ - "futures-io", - "futures-util", - "log", - "pin-project-lite", - "tokio", - "tokio-rustls 0.22.0", - "tungstenite", - "webpki-roots 0.21.1", -] - [[package]] name = "async_io_stream" version = "0.3.3" @@ -356,51 +318,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "axum" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" -dependencies = [ - "async-trait", - "axum-core", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http", - "http-body", - "hyper", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - [[package]] name = "backtrace" version = "0.3.67" @@ -416,12 +333,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - [[package]] name = "base16ct" version = "0.2.0" @@ -464,12 +375,6 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf9ff0bbfd639f15c74af777d81383cf53efb7c93613f6cab67c6c11e05bbf8b" -[[package]] -name = "bech32" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" - [[package]] name = "bellman" version = "0.13.1" @@ -533,39 +438,12 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" -[[package]] -name = "bitcoin" -version = "0.29.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0694ea59225b0c5f3cb405ff3f670e4828358ed26aec49dc352f730f0cb1a8a3" -dependencies = [ - "bech32 0.9.1", - "bitcoin_hashes", - "secp256k1", - "serde", -] - -[[package]] -name = "bitcoin_hashes" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" -dependencies = [ - "serde", -] - [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitflags" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" - [[package]] name = "bitvec" version = "0.17.4" @@ -706,17 +584,40 @@ name = "borsh" version = "0.9.4" source = "git+https://github.com/heliaxdev/borsh-rs.git?rev=cd5223e5103c4f139e0c54cf8259b7ec5ec4073a#cd5223e5103c4f139e0c54cf8259b7ec5ec4073a" dependencies = [ - "borsh-derive", + "borsh-derive 0.9.4", "hashbrown 0.11.2", ] +[[package]] +name = "borsh" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +dependencies = [ + "borsh-derive 0.10.3", + "hashbrown 0.12.3", +] + [[package]] name = "borsh-derive" version = "0.9.4" source = "git+https://github.com/heliaxdev/borsh-rs.git?rev=cd5223e5103c4f139e0c54cf8259b7ec5ec4073a#cd5223e5103c4f139e0c54cf8259b7ec5ec4073a" dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", + "borsh-derive-internal 0.9.4", + "borsh-schema-derive-internal 0.9.4", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" +dependencies = [ + "borsh-derive-internal 0.10.3", + "borsh-schema-derive-internal 0.10.3", "proc-macro-crate 0.1.5", "proc-macro2", "syn 1.0.109", @@ -732,6 +633,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "borsh-derive-internal" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "borsh-schema-derive-internal" version = "0.9.4" @@ -742,6 +654,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "bs58" version = "0.4.0" @@ -791,12 +714,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "bytecount" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c" - [[package]] name = "byteorder" version = "1.4.3" @@ -830,19 +747,6 @@ dependencies = [ "serde", ] -[[package]] -name = "cargo_metadata" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" -dependencies = [ - "camino", - "cargo-platform", - "semver 1.0.17", - "serde", - "serde_json", -] - [[package]] name = "cargo_metadata" version = "0.15.4" @@ -953,18 +857,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.11" +version = "4.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1640e5cc7fb47dbb8338fd471b105e7ed6c3cb2aeb00c2e067127ffd3764a05d" +checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.3.11" +version = "4.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c59138d527eeaf9b53f35a77fcc1fad9d883116070c63d5de1c7dc7b00c72b" +checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" dependencies = [ "anstream", "anstyle", @@ -995,7 +899,7 @@ dependencies = [ "digest 0.10.6", "getrandom 0.2.9", "hmac 0.12.1", - "k256 0.13.1", + "k256", "lazy_static", "serde", "sha2 0.10.6", @@ -1254,18 +1158,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -[[package]] -name = "crypto-bigint" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" -dependencies = [ - "generic-array 0.14.7", - "rand_core 0.6.4", - "subtle 2.4.1", - "zeroize", -] - [[package]] name = "crypto-bigint" version = "0.5.2" @@ -1408,15 +1300,6 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" -[[package]] -name = "der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid", -] - [[package]] name = "der" version = "0.7.7" @@ -1494,16 +1377,6 @@ dependencies = [ "dirs-sys", ] -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if 1.0.0", - "dirs-sys-next", -] - [[package]] name = "dirs-sys" version = "0.3.7" @@ -1515,17 +1388,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - [[package]] name = "displaydoc" version = "0.2.4" @@ -1555,7 +1417,7 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "add9a102807b524ec050363f09e06f1504214b0e1c7797f64261c891022dce8b" dependencies = [ - "bitflags 1.3.2", + "bitflags", "byteorder", "lazy_static", "proc-macro-error", @@ -1575,28 +1437,16 @@ dependencies = [ "memmap2", ] -[[package]] -name = "ecdsa" -version = "0.14.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" -dependencies = [ - "der 0.6.1", - "elliptic-curve 0.12.3", - "rfc6979 0.3.1", - "signature 1.6.4", -] - [[package]] name = "ecdsa" version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428" dependencies = [ - "der 0.7.7", + "der", "digest 0.10.6", - "elliptic-curve 0.13.5", - "rfc6979 0.4.0", + "elliptic-curve", + "rfc6979", "signature 2.1.0", "spki", ] @@ -1642,58 +1492,27 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ed25519-dalek-bip32" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d2be62a4061b872c8c0873ee4fc6f101ce7b889d039f019c5fa2af471a59908" -dependencies = [ - "derivation-path", - "ed25519-dalek", - "hmac 0.12.1", - "sha2 0.10.6", -] - [[package]] name = "either" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" -[[package]] -name = "elliptic-curve" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" -dependencies = [ - "base16ct 0.1.1", - "crypto-bigint 0.4.9", - "der 0.6.1", - "digest 0.10.6", - "ff 0.12.1", - "generic-array 0.14.7", - "group 0.12.1", - "rand_core 0.6.4", - "sec1 0.3.0", - "subtle 2.4.1", - "zeroize", -] - [[package]] name = "elliptic-curve" version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" dependencies = [ - "base16ct 0.2.0", - "crypto-bigint 0.5.2", + "base16ct", + "crypto-bigint", "digest 0.10.6", "ff 0.13.0", "generic-array 0.14.7", "group 0.13.0", "pkcs8", "rand_core 0.6.4", - "sec1 0.7.2", + "sec1", "subtle 2.4.1", "zeroize", ] @@ -1716,7 +1535,7 @@ dependencies = [ "base64 0.13.1", "bytes", "hex", - "k256 0.13.1", + "k256", "log", "rand 0.8.5", "rlp", @@ -1802,15 +1621,6 @@ dependencies = [ "libc", ] -[[package]] -name = "error-chain" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" -dependencies = [ - "version_check", -] - [[package]] name = "eth-keystore" version = "0.5.0" @@ -1830,7 +1640,7 @@ dependencies = [ "sha2 0.10.6", "sha3", "thiserror", - "uuid 0.8.2", + "uuid", ] [[package]] @@ -2031,13 +1841,13 @@ checksum = "6da5fa198af0d3be20c19192df2bd9590b92ce09a8421e793bec8851270f1b05" dependencies = [ "arrayvec", "bytes", - "cargo_metadata 0.15.4", + "cargo_metadata", "chrono", - "elliptic-curve 0.13.5", + "elliptic-curve", "ethabi", "generic-array 0.14.7", "hex", - "k256 0.13.1", + "k256", "num_enum", "once_cell", "open-fastrlp", @@ -2140,7 +1950,7 @@ dependencies = [ "async-trait", "coins-bip32", "coins-bip39", - "elliptic-curve 0.13.5", + "elliptic-curve", "eth-keystore", "ethers-core", "hex", @@ -2197,7 +2007,7 @@ dependencies = [ "bincode", "blake2", "blake2b_simd", - "borsh", + "borsh 0.9.4", "digest 0.10.6", "ed25519-dalek", "either", @@ -2496,12 +2306,6 @@ version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - [[package]] name = "gloo-timers" version = "0.2.6" @@ -2639,15 +2443,6 @@ dependencies = [ "fxhash", ] -[[package]] -name = "hdpath" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ae1615f843ce3981b47468f3f7c435ac17deb33c2261e64d7f1e87f5c11acc" -dependencies = [ - "byteorder", -] - [[package]] name = "headers" version = "0.3.8" @@ -2655,7 +2450,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" dependencies = [ "base64 0.13.1", - "bitflags 1.3.2", + "bitflags", "bytes", "headers-core", "http", @@ -2801,22 +2596,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "humantime-serde" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c" -dependencies = [ - "humantime", - "serde", -] - [[package]] name = "hyper" version = "0.14.26" @@ -2853,9 +2632,9 @@ dependencies = [ "http", "hyper", "hyper-rustls", - "rustls-native-certs 0.5.0", + "rustls-native-certs", "tokio", - "tokio-rustls 0.22.0", + "tokio-rustls", "tower-service", "webpki 0.21.4", ] @@ -2871,25 +2650,13 @@ dependencies = [ "hyper", "log", "rustls 0.19.1", - "rustls-native-certs 0.5.0", + "rustls-native-certs", "tokio", - "tokio-rustls 0.22.0", + "tokio-rustls", "webpki 0.21.4", "webpki-roots 0.21.1", ] -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper", - "pin-project-lite", - "tokio", - "tokio-io-timeout", -] - [[package]] name = "iana-time-zone" version = "0.1.56" @@ -2915,8 +2682,8 @@ dependencies = [ [[package]] name = "ibc" -version = "0.36.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs.git?rev=634f4ede136d045dd6f1ff8f4984dd0006aa15f0#634f4ede136d045dd6f1ff8f4984dd0006aa15f0" +version = "0.41.0" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs.git?rev=38a827d3901e590b2935ee5b6b81b4d67c399560#38a827d3901e590b2935ee5b6b81b4d67c399560" dependencies = [ "bytes", "cfg-if 1.0.0", @@ -2947,113 +2714,26 @@ dependencies = [ [[package]] name = "ibc-proto" -version = "0.26.0" -source = "git+https://github.com/heliaxdev/ibc-proto-rs.git?rev=bb16e17a4d9260d5f20516a8eda43fa52377fad2#bb16e17a4d9260d5f20516a8eda43fa52377fad2" +version = "0.30.0" +source = "git+https://github.com/heliaxdev/ibc-proto-rs.git?rev=31892ee743b2af017d5629b2af419ee20b6100c7#31892ee743b2af017d5629b2af419ee20b6100c7" dependencies = [ - "base64 0.13.1", + "base64 0.21.0", + "borsh 0.10.3", "bytes", "flex-error", + "parity-scale-codec", "prost", + "scale-info", "serde", "subtle-encoding", "tendermint-proto", - "tonic", ] [[package]] -name = "ibc-relayer" -version = "0.22.0" -source = "git+https://github.com/heliaxdev/hermes.git?rev=fea6928dace1af3e38c5b223f933c1d07720811d#fea6928dace1af3e38c5b223f933c1d07720811d" -dependencies = [ - "anyhow", - "async-stream", - "bech32 0.9.1", - "bitcoin", - "bs58", - "bytes", - "crossbeam-channel 0.5.8", - "digest 0.10.6", - "dirs-next", - "ed25519", - "ed25519-dalek", - "ed25519-dalek-bip32", - "flex-error", - "futures", - "generic-array 0.14.7", - "hdpath", - "hex", - "http", - "humantime", - "humantime-serde", - "ibc-proto", - "ibc-relayer-types", - "itertools", - "moka", - "num-bigint 0.4.3", - "num-rational 0.4.1", - "prost", - "regex", - "retry", - "ripemd", - "secp256k1", - "semver 1.0.17", - "serde", - "serde_derive", - "serde_json", - "sha2 0.10.6", - "signature 1.6.4", - "strum", - "subtle-encoding", - "tendermint", - "tendermint-light-client", - "tendermint-light-client-verifier", - "tendermint-proto", - "tendermint-rpc", - "thiserror", - "tiny-bip39 1.0.0", - "tiny-keccak", - "tokio", - "toml 0.5.11", - "tonic", - "tracing", - "uuid 1.3.2", -] - -[[package]] -name = "ibc-relayer-types" -version = "0.22.0" -source = "git+https://github.com/heliaxdev/hermes.git?rev=fea6928dace1af3e38c5b223f933c1d07720811d#fea6928dace1af3e38c5b223f933c1d07720811d" -dependencies = [ - "bytes", - "derive_more", - "dyn-clone", - "erased-serde", - "flex-error", - "ibc-proto", - "ics23", - "itertools", - "num-rational 0.4.1", - "primitive-types", - "prost", - "safe-regex", - "serde", - "serde_derive", - "serde_json", - "subtle-encoding", - "tendermint", - "tendermint-light-client-verifier", - "tendermint-proto", - "tendermint-rpc", - "tendermint-testgen", - "time", - "uint", -] - -[[package]] -name = "ics23" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca44b684ce1859cff746ff46f5765ab72e12e3c06f76a8356db8f9a2ecf43f17" +name = "ics23" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca44b684ce1859cff746ff46f5765ab72e12e3c06f76a8356db8f9a2ecf43f17" dependencies = [ "anyhow", "bytes", @@ -3149,7 +2829,7 @@ name = "index-set" version = "0.7.1" source = "git+https://github.com/heliaxdev/index-set?tag=v0.7.1#dc24cdbbe3664514d59f1a4c4031863fc565f1c2" dependencies = [ - "borsh", + "borsh 0.9.4", "serde", ] @@ -3183,15 +2863,6 @@ dependencies = [ "generic-array 0.14.7", ] -[[package]] -name = "input_buffer" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f97967975f448f1a7ddb12b0bc41069d09ed6a1c161a92687e057325db35d413" -dependencies = [ - "bytes", -] - [[package]] name = "instant" version = "0.1.12" @@ -3232,12 +2903,13 @@ checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "is-terminal" -version = "0.4.9" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ "hermit-abi 0.3.1", - "rustix 0.38.4", + "io-lifetimes", + "rustix", "windows-sys 0.48.0", ] @@ -3279,18 +2951,6 @@ dependencies = [ "subtle 2.4.1", ] -[[package]] -name = "k256" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" -dependencies = [ - "cfg-if 1.0.0", - "ecdsa 0.14.8", - "elliptic-curve 0.12.3", - "sha2 0.10.6", -] - [[package]] name = "k256" version = "0.13.1" @@ -3298,8 +2958,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" dependencies = [ "cfg-if 1.0.0", - "ecdsa 0.16.7", - "elliptic-curve 0.13.5", + "ecdsa", + "elliptic-curve", "once_cell", "sha2 0.10.6", "signature 2.1.0", @@ -3328,9 +2988,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "libloading" @@ -3414,12 +3074,6 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" -[[package]] -name = "linux-raw-sys" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" - [[package]] name = "lock_api" version = "0.4.9" @@ -3471,7 +3125,7 @@ name = "masp_note_encryption" version = "0.2.0" source = "git+https://github.com/anoma/masp?rev=252a6059565b125c1444e9e7d0b7c8da0fba8f8f#252a6059565b125c1444e9e7d0b7c8da0fba8f8f" dependencies = [ - "borsh", + "borsh 0.9.4", "chacha20 0.9.1", "chacha20poly1305", "cipher 0.4.4", @@ -3490,7 +3144,7 @@ dependencies = [ "blake2b_simd", "blake2s_simd", "bls12_381", - "borsh", + "borsh 0.9.4", "byteorder", "ff 0.12.1", "fpe", @@ -3539,12 +3193,6 @@ dependencies = [ "regex-automata", ] -[[package]] -name = "matchit" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" - [[package]] name = "maybe-uninit" version = "2.0.0" @@ -3670,29 +3318,6 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94c7128ba23c81f6471141b90f17654f89ef44a56e14b8a4dd0fddfccd655277" -[[package]] -name = "moka" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b9268097a2cf211ac9955b1cc95e80fa84fff5c2d13ba292916445dc8a311f" -dependencies = [ - "crossbeam-channel 0.5.8", - "crossbeam-epoch", - "crossbeam-utils 0.8.15", - "num_cpus", - "once_cell", - "parking_lot", - "quanta", - "rustc_version 0.4.0", - "scheduled-thread-pool", - "skeptic", - "smallvec", - "tagptr", - "thiserror", - "triomphe", - "uuid 1.3.2", -] - [[package]] name = "more-asserts" version = "0.2.2" @@ -3707,11 +3332,11 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "namada" -version = "0.20.1" +version = "0.21.1" dependencies = [ "async-trait", "bimap", - "borsh", + "borsh 0.9.4", "circular-queue", "clru", "data-encoding", @@ -3748,7 +3373,7 @@ dependencies = [ "tempfile", "tendermint-rpc", "thiserror", - "tiny-bip39 0.8.2", + "tiny-bip39", "tiny-hderive", "tokio", "toml 0.5.11", @@ -3767,13 +3392,13 @@ dependencies = [ [[package]] name = "namada_core" -version = "0.20.1" +version = "0.21.1" dependencies = [ "ark-bls12-381", "ark-ec", "ark-serialize", "bech32 0.8.1", - "borsh", + "borsh 0.9.4", "chrono", "data-encoding", "derivative", @@ -3819,9 +3444,9 @@ dependencies = [ [[package]] name = "namada_ethereum_bridge" -version = "0.20.1" +version = "0.21.1" dependencies = [ - "borsh", + "borsh 0.9.4", "ethers", "eyre", "itertools", @@ -3839,7 +3464,7 @@ dependencies = [ [[package]] name = "namada_macros" -version = "0.20.1" +version = "0.21.1" dependencies = [ "proc-macro2", "quote", @@ -3848,9 +3473,9 @@ dependencies = [ [[package]] name = "namada_proof_of_stake" -version = "0.20.1" +version = "0.21.1" dependencies = [ - "borsh", + "borsh 0.9.4", "data-encoding", "derivative", "namada_core", @@ -3862,16 +3487,16 @@ dependencies = [ [[package]] name = "namada_test_utils" -version = "0.20.1" +version = "0.21.1" dependencies = [ - "borsh", + "borsh 0.9.4", "namada_core", "strum", ] [[package]] name = "namada_tests" -version = "0.20.1" +version = "0.21.1" dependencies = [ "async-trait", "chrono", @@ -3879,8 +3504,6 @@ dependencies = [ "concat-idents", "derivative", "hyper", - "ibc-relayer", - "ibc-relayer-types", "lazy_static", "namada", "namada_core", @@ -3890,9 +3513,11 @@ dependencies = [ "num-traits", "prost", "regex", + "serde", "serde_json", "sha2 0.9.9", "tempfile", + "tendermint-light-client", "test-log", "tokio", "tracing", @@ -3901,9 +3526,9 @@ dependencies = [ [[package]] name = "namada_tx_prelude" -version = "0.20.1" +version = "0.21.1" dependencies = [ - "borsh", + "borsh 0.9.4", "masp_primitives", "namada_core", "namada_macros", @@ -3915,18 +3540,18 @@ dependencies = [ [[package]] name = "namada_vm_env" -version = "0.20.1" +version = "0.21.1" dependencies = [ - "borsh", + "borsh 0.9.4", "masp_primitives", "namada_core", ] [[package]] name = "namada_vp_prelude" -version = "0.20.1" +version = "0.21.1" dependencies = [ - "borsh", + "borsh 0.9.4", "namada_core", "namada_macros", "namada_proof_of_stake", @@ -3937,9 +3562,9 @@ dependencies = [ [[package]] name = "namada_wasm" -version = "0.20.1" +version = "0.21.1" dependencies = [ - "borsh", + "borsh 0.9.4", "getrandom 0.2.9", "masp_primitives", "namada", @@ -4009,7 +3634,6 @@ dependencies = [ "autocfg", "num-integer", "num-traits", - "serde", ] [[package]] @@ -4085,7 +3709,6 @@ dependencies = [ "num-bigint 0.4.3", "num-integer", "num-traits", - "serde", ] [[package]] @@ -4462,7 +4085,7 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der 0.7.7", + "der", "spki", ] @@ -4576,7 +4199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e35c06b98bf36aba164cc17cb25f7e232f5c4aeea73baa14b8a9f0d92dbfa65" dependencies = [ "bit-set", - "bitflags 1.3.2", + "bitflags", "byteorder", "lazy_static", "num-traits", @@ -4663,33 +4286,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "pulldown-cmark" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63" -dependencies = [ - "bitflags 1.3.2", - "memchr", - "unicase", -] - -[[package]] -name = "quanta" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e31331286705f455e56cca62e0e717158474ff02b7936c1fa596d983f4ae27" -dependencies = [ - "crossbeam-utils 0.8.15", - "libc", - "mach", - "once_cell", - "raw-cpuid", - "wasi 0.10.2+wasi-snapshot-preview1", - "web-sys", - "winapi", -] - [[package]] name = "quick-error" version = "1.2.3" @@ -4797,15 +4393,6 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "raw-cpuid" -version = "10.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "rayon" version = "1.5.3" @@ -4852,7 +4439,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -4861,7 +4448,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -4924,7 +4511,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" dependencies = [ - "bitflags 1.3.2", + "bitflags", "libc", "mach", "winapi", @@ -4973,23 +4560,6 @@ dependencies = [ "winreg", ] -[[package]] -name = "retry" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9166d72162de3575f950507683fac47e30f6f2c3836b71b7fbc61aa517c9c5f4" - -[[package]] -name = "rfc6979" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" -dependencies = [ - "crypto-bigint 0.4.9", - "hmac 0.12.1", - "zeroize", -] - [[package]] name = "rfc6979" version = "0.4.0" @@ -5024,17 +4594,6 @@ dependencies = [ "digest 0.10.6", ] -[[package]] -name = "ripemd160" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "opaque-debug 0.3.0", -] - [[package]] name = "rkyv" version = "0.7.41" @@ -5124,24 +4683,11 @@ version = "0.37.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" dependencies = [ - "bitflags 1.3.2", + "bitflags", "errno", "io-lifetimes", "libc", - "linux-raw-sys 0.3.7", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustix" -version = "0.38.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" -dependencies = [ - "bitflags 2.3.3", - "errno", - "libc", - "linux-raw-sys 0.4.3", + "linux-raw-sys", "windows-sys 0.48.0", ] @@ -5182,27 +4728,6 @@ dependencies = [ "security-framework", ] -[[package]] -name = "rustls-native-certs" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" -dependencies = [ - "openssl-probe", - "rustls-pemfile", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" -dependencies = [ - "base64 0.21.0", -] - [[package]] name = "rustversion" version = "1.0.12" @@ -5325,15 +4850,6 @@ dependencies = [ "windows-sys 0.42.0", ] -[[package]] -name = "scheduled-thread-pool" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" -dependencies = [ - "parking_lot", -] - [[package]] name = "scopeguard" version = "1.1.0" @@ -5378,61 +4894,27 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" -[[package]] -name = "sec1" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" -dependencies = [ - "base16ct 0.1.1", - "der 0.6.1", - "generic-array 0.14.7", - "subtle 2.4.1", - "zeroize", -] - [[package]] name = "sec1" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0aec48e813d6b90b15f0b8948af3c63483992dee44c03e9930b3eebdabe046e" dependencies = [ - "base16ct 0.2.0", - "der 0.7.7", + "base16ct", + "der", "generic-array 0.14.7", "pkcs8", "subtle 2.4.1", "zeroize", ] -[[package]] -name = "secp256k1" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" -dependencies = [ - "bitcoin_hashes", - "rand 0.8.5", - "secp256k1-sys", - "serde", -] - -[[package]] -name = "secp256k1-sys" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" -dependencies = [ - "cc", -] - [[package]] name = "security-framework" version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" dependencies = [ - "bitflags 1.3.2", + "bitflags", "core-foundation", "core-foundation-sys", "libc", @@ -5570,19 +5052,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha-1" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.9.0", - "opaque-debug 0.3.0", -] - [[package]] name = "sha1" version = "0.10.5" @@ -5663,10 +5132,6 @@ name = "signature" version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" -dependencies = [ - "digest 0.10.6", - "rand_core 0.6.4", -] [[package]] name = "signature" @@ -5690,21 +5155,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc47a29ce97772ca5c927f75bac34866b16d64e07f330c3248e2d7226623901b" -[[package]] -name = "skeptic" -version = "0.13.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" -dependencies = [ - "bytecount", - "cargo_metadata 0.14.2", - "error-chain", - "glob", - "pulldown-cmark", - "tempfile", - "walkdir", -] - [[package]] name = "slab" version = "0.4.8" @@ -5744,7 +5194,7 @@ name = "sparse-merkle-tree" version = "0.3.1-pre" source = "git+https://github.com/heliaxdev/sparse-merkle-tree?rev=e086b235ed6e68929bf73f617dd61cd17b000a56#e086b235ed6e68929bf73f617dd61cd17b000a56" dependencies = [ - "borsh", + "borsh 0.9.4", "cfg-if 1.0.0", "ics23", "sha2 0.9.9", @@ -5763,7 +5213,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" dependencies = [ "base64ct", - "der 0.7.7", + "der", ] [[package]] @@ -5868,18 +5318,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "tagptr" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" - [[package]] name = "tap" version = "1.0.1" @@ -5901,7 +5339,7 @@ dependencies = [ "cfg-if 1.0.0", "fastrand", "redox_syscall 0.3.5", - "rustix 0.37.19", + "rustix", "windows-sys 0.45.0", ] @@ -5916,12 +5354,10 @@ dependencies = [ "ed25519-dalek", "flex-error", "futures", - "k256 0.11.6", "num-traits", "once_cell", "prost", "prost-types", - "ripemd160", "serde", "serde_bytes", "serde_json", @@ -6004,7 +5440,6 @@ version = "0.23.6" source = "git+https://github.com/heliaxdev/tendermint-rs.git?rev=b7d1e5afc6f2ccb3fd1545c2174bab1cc48d7fa7#b7d1e5afc6f2ccb3fd1545c2174bab1cc48d7fa7" dependencies = [ "async-trait", - "async-tungstenite", "bytes", "flex-error", "futures", @@ -6027,7 +5462,7 @@ dependencies = [ "tokio", "tracing", "url", - "uuid 0.8.2", + "uuid", "walkdir", ] @@ -6131,25 +5566,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "tiny-bip39" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62cc94d358b5a1e84a5cb9109f559aa3c4d634d2b1b4de3d0fa4adc7c78e2861" -dependencies = [ - "anyhow", - "hmac 0.12.1", - "once_cell", - "pbkdf2 0.11.0", - "rand 0.8.5", - "rustc-hash", - "sha2 0.10.6", - "thiserror", - "unicode-normalization", - "wasm-bindgen", - "zeroize", -] - [[package]] name = "tiny-hderive" version = "0.3.0" @@ -6206,16 +5622,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "tokio-io-timeout" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" -dependencies = [ - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-macros" version = "2.1.0" @@ -6238,28 +5644,6 @@ dependencies = [ "webpki 0.21.4", ] -[[package]] -name = "tokio-rustls" -version = "0.23.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" -dependencies = [ - "rustls 0.20.8", - "tokio", - "webpki 0.22.0", -] - -[[package]] -name = "tokio-stream" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.8" @@ -6317,41 +5701,6 @@ dependencies = [ "winnow", ] -[[package]] -name = "tonic" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64 0.13.1", - "bytes", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost", - "prost-derive", - "rustls-native-certs 0.6.2", - "rustls-pemfile", - "tokio", - "tokio-rustls 0.23.4", - "tokio-stream", - "tokio-util", - "tower", - "tower-layer", - "tower-service", - "tracing", - "tracing-futures", -] - [[package]] name = "tonic-build" version = "0.8.4" @@ -6365,32 +5714,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand 0.8.5", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - [[package]] name = "tower-service" version = "0.3.2" @@ -6455,42 +5778,17 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "triomphe" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1ee9bd9239c339d714d657fac840c6d2a4f9c45f4f9ec7b0975113458be78db" - [[package]] name = "try-lock" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" -[[package]] -name = "tungstenite" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ada8297e8d70872fa9a551d93250a9f407beb9f37ef86494eb20012a2ff7c24" -dependencies = [ - "base64 0.13.1", - "byteorder", - "bytes", - "http", - "httparse", - "input_buffer", - "log", - "rand 0.8.5", - "sha-1", - "url", - "utf-8", -] - [[package]] name = "tx_template" -version = "0.20.1" +version = "0.21.1" dependencies = [ - "borsh", + "borsh 0.9.4", "getrandom 0.2.9", "namada_tests", "namada_tx_prelude", @@ -6527,15 +5825,6 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-bidi" version = "0.3.13" @@ -6596,12 +5885,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8parse" version = "0.2.1" @@ -6618,15 +5901,6 @@ dependencies = [ "serde", ] -[[package]] -name = "uuid" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dad5567ad0cf5b760e5665964bec1b47dfd077ba8a2544b513f3556d3d239a2" -dependencies = [ - "getrandom 0.2.9", -] - [[package]] name = "version_check" version = "0.9.4" @@ -6635,9 +5909,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vp_template" -version = "0.20.1" +version = "0.21.1" dependencies = [ - "borsh", + "borsh 0.9.4", "getrandom 0.2.9", "namada_tests", "namada_vp_prelude", @@ -6679,12 +5953,6 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -[[package]] -name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/wasm/checksums.json b/wasm/checksums.json index cb9ca8ed52..71b5580e4a 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,21 +1,21 @@ { - "tx_bond.wasm": "tx_bond.08cedac1d825cd8ee9b04ef059bc68fee04f82fec57e0f6bc38123de8fb35b85.wasm", - "tx_bridge_pool.wasm": "tx_bridge_pool.c9ef2bdb19910e12eadabc7f0552b45c937bcf1f47ca09759e52112b68d94114.wasm", - "tx_change_validator_commission.wasm": "tx_change_validator_commission.2be60082c6b891cb437b4392e1b2570f5d92fed35dd624cd079ea48c4bc7902c.wasm", - "tx_ibc.wasm": "tx_ibc.f8056f465d17043d2864309d1c50a897a028b6ebf9702e5c403e1bf8c670f6e6.wasm", - "tx_init_account.wasm": "tx_init_account.e91ab25cebd15af9a958eca4a34ba287804b1ff6ba4c82fc941f7f50816e9c4d.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.1683eb9a2b2616af21f4f55457f7e06e0ae0591f460ede412a548ea9b1ab694c.wasm", - "tx_init_validator.wasm": "tx_init_validator.67574f70c1f76c2c68498d17323793366c13d119480b6787c8c5ede312e51da0.wasm", - "tx_reveal_pk.wasm": "tx_reveal_pk.e6375abba3f750700c06fbdeb2d5edec22b6a382116a67a7f9d7f7ba49f134e1.wasm", - "tx_transfer.wasm": "tx_transfer.e65b47bc94c5a09e3edc68298ad0e5e35041b91bc4d679bf5b7f433dffdce58e.wasm", - "tx_unbond.wasm": "tx_unbond.4fd70d297ccedb369bf88d8a8459a47ea733d329410387a6f80a0e026c6e480d.wasm", - "tx_unjail_validator.wasm": "tx_unjail_validator.b8e7204b14e15a3c395432f35788eca45ef4332916d96dfba87627a5717916de.wasm", - "tx_update_vp.wasm": "tx_update_vp.65c5ca3e48fdef70e696460eca7540cf6196511d76fb2465133b145409329b3e.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.e0a003d922230d32b741b57ca18913cbc4d5d2290f02cb37dfdaa7f27cebb486.wasm", - "tx_withdraw.wasm": "tx_withdraw.40499cb0e268d3cc3d9bca5dacca05d8df35f5b90adf4087a5171505472d921a.wasm", - "vp_implicit.wasm": "vp_implicit.57af3b7d2ee9e2c9d7ef1e33a85646abeea7ea02dad19b7e0b20b289de5a7ae9.wasm", - "vp_masp.wasm": "vp_masp.4d656f775b7462095e7d9ff533e346829fad02568b1cf92fa2f99cc0677720ce.wasm", - "vp_testnet_faucet.wasm": "vp_testnet_faucet.b0c855f0356a468db1d26baebc988508d4824836b86adb94ac432368feb03ac4.wasm", - "vp_user.wasm": "vp_user.31967a7411caf61729e46840eec90d2db386cf4745f49d59086a43cc3c3e2d39.wasm", - "vp_validator.wasm": "vp_validator.0bca8e34f5d51c74b2861d588e3dd6a8e61de7c63d356af63e2182e030ac42ee.wasm" + "tx_bond.wasm": "tx_bond.0967203d10b78f7f28c3e1d674c0ff3ec25ec00e9b3a4010648c5cc381ad52ec.wasm", + "tx_bridge_pool.wasm": "tx_bridge_pool.c6dd30e79edff950016f495cee946bc6c0d6847f89322fbf733c89bb768c1fd4.wasm", + "tx_change_validator_commission.wasm": "tx_change_validator_commission.1e89cf7f091a324872582c1092f2bda662be21040ac796d8aca08d08e9332a3e.wasm", + "tx_ibc.wasm": "tx_ibc.2b35a3a35049fe267121906176bafc0ea2b221a185fe31652216f93da66209e7.wasm", + "tx_init_account.wasm": "tx_init_account.6e77218b385a386f49c65c13b6112c75dcb06c50cf7bf7a5a479e7e8b7b458fa.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.d0c969c6b7a3d262d82586c630f29a00e587653fa9df1cf17021914764d4d3ab.wasm", + "tx_init_validator.wasm": "tx_init_validator.df780e2cc9ab4a5726931b662fd75cad907e495745aec1c466877878cee1ae3a.wasm", + "tx_reveal_pk.wasm": "tx_reveal_pk.062b11c679a35e50f7fcfca95e3ada01bc89098591ae92526cfafaab5adf954e.wasm", + "tx_transfer.wasm": "tx_transfer.5f9e5a2f85fa5c1ec2bbb0aa9bebaba6bddc7e777ca956f5d980ad1cc9af3e7e.wasm", + "tx_unbond.wasm": "tx_unbond.dc169426d36f2bcfd82d976e77e2f3beb85ac98e75652ddf8367fa081fb17b3d.wasm", + "tx_unjail_validator.wasm": "tx_unjail_validator.23d1b075f28d5fa3ee413ee4db31792a2714d9b21929cbf1ba59832c3adec886.wasm", + "tx_update_account.wasm": "tx_update_account.88646c9fb5d3327701d69b12ce49ae35431ebe2ea3691900874cad66791f1ca9.wasm", + "tx_vote_proposal.wasm": "tx_vote_proposal.c9abcd6f37d59daf9a39e30dcebd9e0789d5bcd679f5931ed7899073d0a5d36f.wasm", + "tx_withdraw.wasm": "tx_withdraw.02ac0399bc5b745346641facd968607931bf9abf67d7ed336b6b0540360f2d43.wasm", + "vp_implicit.wasm": "vp_implicit.1d212280efc3fccc16de9497dae8cc1670f21f0e0ce4c3bd9fc58fc816037cdf.wasm", + "vp_masp.wasm": "vp_masp.1d264f4ba602df546011ae4040da00bd0b103c6bad62ee5de985940e8bf0c2e7.wasm", + "vp_testnet_faucet.wasm": "vp_testnet_faucet.d279129573a4f0625f411c7b147ac94bc40e0db2ea04b777f29e57be33a53522.wasm", + "vp_user.wasm": "vp_user.788b8039744b73bd6fe2b67b273802bae4c26cd117092eb8437f455d5aa95dbd.wasm", + "vp_validator.wasm": "vp_validator.98457b70476c76a16b1cd28232bacf043438bfd5e054bc9f7651ef1747e48594.wasm" } \ No newline at end of file diff --git a/wasm/tx_template/Cargo.toml b/wasm/tx_template/Cargo.toml index ab661039f9..aece3dba98 100644 --- a/wasm/tx_template/Cargo.toml +++ b/wasm/tx_template/Cargo.toml @@ -4,7 +4,7 @@ edition = "2021" license = "GPL-3.0" name = "tx_template" resolver = "2" -version = "0.20.1" +version = "0.21.1" [lib] crate-type = ["cdylib"] diff --git a/wasm/tx_template/src/lib.rs b/wasm/tx_template/src/lib.rs index 4a14783325..5b0f8fb501 100644 --- a/wasm/tx_template/src/lib.rs +++ b/wasm/tx_template/src/lib.rs @@ -19,7 +19,7 @@ mod tests { // The environment must be initialized first tx_host_env::init(); - let tx = Tx::new(TxType::Raw); + let tx = Tx::from_type(TxType::Raw); apply_tx(ctx(), tx).unwrap(); let env = tx_host_env::take(); diff --git a/wasm/vp_template/Cargo.toml b/wasm/vp_template/Cargo.toml index 5d2ecf553e..f5286efeef 100644 --- a/wasm/vp_template/Cargo.toml +++ b/wasm/vp_template/Cargo.toml @@ -4,7 +4,7 @@ edition = "2021" license = "GPL-3.0" name = "vp_template" resolver = "2" -version = "0.20.1" +version = "0.21.1" [lib] crate-type = ["cdylib"] diff --git a/wasm/wasm_source/Cargo.toml b/wasm/wasm_source/Cargo.toml index d25f6d8b9a..e5ca25f581 100644 --- a/wasm/wasm_source/Cargo.toml +++ b/wasm/wasm_source/Cargo.toml @@ -4,7 +4,7 @@ edition = "2021" license = "GPL-3.0" name = "namada_wasm" resolver = "2" -version = "0.20.1" +version = "0.21.1" [lib] crate-type = ["cdylib"] @@ -24,7 +24,7 @@ tx_reveal_pk = ["namada_tx_prelude"] tx_transfer = ["namada_tx_prelude"] tx_unbond = ["namada_tx_prelude"] tx_unjail_validator = ["namada_tx_prelude"] -tx_update_vp = ["namada_tx_prelude"] +tx_update_account = ["namada_tx_prelude"] tx_vote_proposal = ["namada_tx_prelude"] tx_withdraw = ["namada_tx_prelude"] vp_implicit = ["namada_vp_prelude", "once_cell"] diff --git a/wasm/wasm_source/Makefile b/wasm/wasm_source/Makefile index f394179dc7..a88065355f 100644 --- a/wasm/wasm_source/Makefile +++ b/wasm/wasm_source/Makefile @@ -16,7 +16,7 @@ wasms += tx_reveal_pk wasms += tx_transfer wasms += tx_unbond wasms += tx_unjail_validator -wasms += tx_update_vp +wasms += tx_update_account wasms += tx_vote_proposal wasms += tx_withdraw wasms += vp_implicit diff --git a/wasm/wasm_source/src/lib.rs b/wasm/wasm_source/src/lib.rs index 2fc69f65c9..ce5b1b1561 100644 --- a/wasm/wasm_source/src/lib.rs +++ b/wasm/wasm_source/src/lib.rs @@ -20,8 +20,8 @@ pub mod tx_transfer; pub mod tx_unbond; #[cfg(feature = "tx_unjail_validator")] pub mod tx_unjail_validator; -#[cfg(feature = "tx_update_vp")] -pub mod tx_update_vp; +#[cfg(feature = "tx_update_account")] +pub mod tx_update_account; #[cfg(feature = "tx_vote_proposal")] pub mod tx_vote_proposal; #[cfg(feature = "tx_withdraw")] diff --git a/wasm/wasm_source/src/tx_bond.rs b/wasm/wasm_source/src/tx_bond.rs index 33d004591b..f9a6ab9c60 100644 --- a/wasm/wasm_source/src/tx_bond.rs +++ b/wasm/wasm_source/src/tx_bond.rs @@ -22,10 +22,8 @@ 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_tests::log::test; use namada_tests::native_vp::pos::init_pos; use namada_tests::native_vp::TestNativeVpEnv; @@ -34,6 +32,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 +107,12 @@ 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 mut tx = Tx::new(ChainId::default(), None); + tx.add_code(tx_code) + .add_serialized_data(tx_data) + .sign_wrapper(key); + + 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..ee3685b191 100644 --- a/wasm/wasm_source/src/tx_change_validator_commission.rs +++ b/wasm/wasm_source/src/tx_change_validator_commission.rs @@ -21,15 +21,14 @@ 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_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 +86,12 @@ 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 mut tx = Tx::new(ChainId::default(), None); + tx.add_code(tx_code) + .add_serialized_data(tx_data) + .sign_wrapper(key); + + let signed_tx = tx; // Read the data before the tx is executed let commission_rate_handle = diff --git a/wasm/wasm_source/src/tx_init_account.rs b/wasm/wasm_source/src/tx_init_account.rs index 2e85b70ae9..346afb2bec 100644 --- a/wasm/wasm_source/src/tx_init_account.rs +++ b/wasm/wasm_source/src/tx_init_account.rs @@ -7,7 +7,7 @@ use namada_tx_prelude::*; fn apply_tx(ctx: &mut Ctx, tx_data: Tx) -> TxResult { let signed = tx_data; let data = signed.data().ok_or_err_msg("Missing data")?; - let tx_data = transaction::InitAccount::try_from_slice(&data[..]) + let tx_data = transaction::account::InitAccount::try_from_slice(&data[..]) .wrap_err("failed to decode InitAccount")?; debug_log!("apply_tx called to init a new established account"); @@ -18,8 +18,17 @@ fn apply_tx(ctx: &mut Ctx, tx_data: Tx) -> TxResult { .ok_or_err_msg("vp code section must be tagged as extra")? .code .hash(); + let address = ctx.init_account(vp_code)?; - let pk_key = key::pk_key(&address); - ctx.write(&pk_key, &tx_data.public_key)?; + + match account::init_account(ctx, &address, tx_data) { + Ok(address) => { + debug_log!("Created account {}", address.encode(),) + } + Err(err) => { + debug_log!("Account creation failed with: {}", err); + panic!() + } + } Ok(()) } diff --git a/wasm/wasm_source/src/tx_init_proposal.rs b/wasm/wasm_source/src/tx_init_proposal.rs index c0da1d9316..e11ebb7a61 100644 --- a/wasm/wasm_source/src/tx_init_proposal.rs +++ b/wasm/wasm_source/src/tx_init_proposal.rs @@ -8,22 +8,26 @@ fn apply_tx(ctx: &mut Ctx, tx: Tx) -> TxResult { let tx_data = transaction::governance::InitProposalData::try_from_slice(&data[..]) .wrap_err("failed to decode InitProposalData")?; + // Get the content from the referred to section let content = tx .get_section(&tx_data.content) .ok_or_err_msg("Missing proposal content")? .extra_data() .ok_or_err_msg("Missing full proposal content")?; + // Get the code from the referred to section - let code = match tx_data.r#type { - transaction::governance::ProposalType::Default(Some(hash)) => Some( + let code_hash = tx_data.get_section_code_hash(); + let code = match code_hash { + Some(hash) => Some( tx.get_section(&hash) .ok_or_err_msg("Missing proposal code")? .extra_data() .ok_or_err_msg("Missing full proposal code")?, ), - _ => None, + None => None, }; + log_string("apply_tx called to create a new governance proposal"); governance::init_proposal(ctx, tx_data, content, code) diff --git a/wasm/wasm_source/src/tx_init_validator.rs b/wasm/wasm_source/src/tx_init_validator.rs index 0cd37da111..eb80ec444e 100644 --- a/wasm/wasm_source/src/tx_init_validator.rs +++ b/wasm/wasm_source/src/tx_init_validator.rs @@ -1,7 +1,7 @@ //! A tx to initialize a new validator account with a given public keys and a //! validity predicates. -use namada_tx_prelude::transaction::InitValidator; +use namada_tx_prelude::transaction::pos::InitValidator; use namada_tx_prelude::*; #[transaction] diff --git a/wasm/wasm_source/src/tx_unbond.rs b/wasm/wasm_source/src/tx_unbond.rs index e453d48b14..90b22734a0 100644 --- a/wasm/wasm_source/src/tx_unbond.rs +++ b/wasm/wasm_source/src/tx_unbond.rs @@ -23,15 +23,14 @@ 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_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; @@ -127,14 +126,11 @@ 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 mut tx = Tx::new(ChainId::default(), None); + tx.add_code(tx_code) + .add_serialized_data(tx_data) + .sign_wrapper(key); + let signed_tx = tx; let unbond_src = unbond .source diff --git a/wasm/wasm_source/src/tx_update_account.rs b/wasm/wasm_source/src/tx_update_account.rs new file mode 100644 index 0000000000..c2553759e5 --- /dev/null +++ b/wasm/wasm_source/src/tx_update_account.rs @@ -0,0 +1,45 @@ +//! A tx for updating an account's validity predicate. +//! This tx wraps the validity predicate inside `SignedTxData` as +//! its input as declared in `shared` crate. + +use namada_tx_prelude::key::pks_handle; +use namada_tx_prelude::*; + +#[transaction] +fn apply_tx(ctx: &mut Ctx, tx: Tx) -> TxResult { + let signed = tx; + let data = signed.data().ok_or_err_msg("Missing data")?; + let tx_data = + transaction::account::UpdateAccount::try_from_slice(&data[..]) + .wrap_err("failed to decode UpdateAccount")?; + + let owner = &tx_data.addr; + debug_log!("update VP for: {:#?}", tx_data.addr); + + if let Some(hash) = tx_data.vp_code_hash { + let vp_code_hash = signed + .get_section(&hash) + .ok_or_err_msg("vp code section not found")? + .extra_data_sec() + .ok_or_err_msg("vp code section must be tagged as extra")? + .code + .hash(); + + ctx.update_validity_predicate(owner, vp_code_hash)?; + } + + if let Some(threshold) = tx_data.threshold { + let threshold_key = key::threshold_key(owner); + ctx.write(&threshold_key, threshold)?; + } + + if !tx_data.public_keys.is_empty() { + storage_api::account::clear_public_keys(ctx, owner)?; + for (index, public_key) in tx_data.public_keys.iter().enumerate() { + let index = index as u8; + pks_handle(owner).insert(ctx, index, public_key.clone())?; + } + } + + Ok(()) +} diff --git a/wasm/wasm_source/src/tx_withdraw.rs b/wasm/wasm_source/src/tx_withdraw.rs index 20b202bdb6..dd40e044b3 100644 --- a/wasm/wasm_source/src/tx_withdraw.rs +++ b/wasm/wasm_source/src/tx_withdraw.rs @@ -22,10 +22,8 @@ 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_tests::log::test; use namada_tests::native_vp::pos::init_pos; use namada_tests::native_vp::TestNativeVpEnv; @@ -34,6 +32,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; @@ -171,14 +170,11 @@ 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 mut tx = Tx::new(ChainId::default(), None); + tx.add_code(tx_code) + .add_serialized_data(tx_data) + .sign_wrapper(key); + let signed_tx = tx; // Read data before we apply tx: let pos_balance_key = token::balance_key( diff --git a/wasm/wasm_source/src/vp_implicit.rs b/wasm/wasm_source/src/vp_implicit.rs index f82c573bc1..9da84d1776 100644 --- a/wasm/wasm_source/src/vp_implicit.rs +++ b/wasm/wasm_source/src/vp_implicit.rs @@ -28,14 +28,14 @@ enum KeyType<'a> { impl<'a> From<&'a storage::Key> for KeyType<'a> { fn from(key: &'a storage::Key) -> KeyType<'a> { - if let Some(address) = key::is_pk_key(key) { + if let Some(address) = key::is_pks_key(key) { Self::Pk(address) } else if let Some([_, owner]) = token::is_any_token_balance_key(key) { Self::Token { owner } } else if proof_of_stake::is_pos_key(key) { Self::PoS - } else if gov_storage::is_vote_key(key) { - let voter_address = gov_storage::get_voter_address(key); + } else if gov_storage::keys::is_vote_key(key) { + let voter_address = gov_storage::keys::get_voter_address(key); if let Some(address) = voter_address { Self::GovernanceVote(address) } else { @@ -62,18 +62,8 @@ fn validate_tx( verifiers ); - let valid_sig = Lazy::new(|| { - let pk = key::get(ctx, &addr); - match pk { - Ok(Some(pk)) => tx_data - .verify_signature( - &pk, - &[*tx_data.data_sechash(), *tx_data.code_sechash()], - ) - .is_ok(), - _ => false, - } - }); + let valid_sig = + Lazy::new(|| verify_signatures(ctx, &tx_data, &addr).is_ok()); if !is_valid_tx(ctx, &tx_data)? { return reject(); @@ -196,7 +186,7 @@ fn validate_tx( mod tests { // Use this as `#[test]` annotation to enable logging use namada::ledger::pos::{GenesisValidator, PosParams}; - use namada::proto::{Code, Data, Signature}; + use namada::proto::{Code, Data, MultiSignature}; use namada::types::dec::Dec; use namada::types::storage::Epoch; use namada::types::transaction::TxType; @@ -207,6 +197,7 @@ mod tests { use namada_tests::vp::vp_host_env::storage::Key; use namada_tests::vp::*; use namada_tx_prelude::{storage_api, StorageWrite, TxEnv}; + use namada_vp_prelude::account::AccountPublicKeysMap; use namada_vp_prelude::key::RefTo; use proptest::prelude::*; use storage::testing::arb_account_storage_key_no_vp; @@ -216,7 +207,7 @@ mod tests { /// Test that no-op transaction (i.e. no storage modifications) accepted. #[test] fn test_no_op_transaction() { - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let addr: Address = address::testing::established_address_1(); let keys_changed: BTreeSet = BTreeSet::default(); @@ -240,7 +231,8 @@ mod tests { let addr: Address = (&public_key).into(); // Initialize a tx environment - let tx_env = TestTxEnv::default(); + let mut tx_env = TestTxEnv::default(); + tx_env.init_parameters(None, None, None, None); // Initialize VP environment from a transaction vp_host_env::init_from_tx(addr.clone(), tx_env, |_address| { @@ -249,7 +241,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -276,7 +268,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -308,12 +300,16 @@ mod tests { // Initialize VP environment from a transaction vp_host_env::init_from_tx(addr.clone(), tx_env, |_address| { // Do the same as reveal_pk, but with the wrong key - let key = namada_tx_prelude::key::pk_key(&addr); - tx_host_env::ctx().write(&key, &mismatched_pk).unwrap(); + let _ = storage_api::account::set_public_key_at( + tx_host_env::ctx(), + &addr, + &mismatched_pk, + 0, + ); }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -373,7 +369,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -414,6 +410,8 @@ mod tests { // Initialize a tx environment let mut tx_env = tx_host_env::take(); + tx_env.init_parameters(None, Some(vec![]), Some(vec![]), None); + let secret_key = key::testing::keypair_1(); let public_key = secret_key.ref_to(); let vp_owner: Address = (&public_key).into(); @@ -425,6 +423,7 @@ mod tests { // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&target, &token]); + tx_env.init_account_storage(&vp_owner, vec![public_key], 1); // Credit the tokens to the VP owner before running the transaction to // be able to transfer from it @@ -449,7 +448,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -461,8 +460,8 @@ mod tests { ); } - /// Test that a PoS action that must be authorized is accepted with a valid - /// signature. + /// Test that a PoS action that must be authorized is accepted with a + /// valid signature. #[test] fn test_signed_pos_action_accepted() { // Init PoS genesis @@ -505,6 +504,7 @@ mod tests { // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&target, &token]); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Credit the tokens to the VP owner before running the transaction to // be able to transfer from it @@ -517,8 +517,6 @@ mod tests { ) .unwrap(); - tx_env.write_public_key(&vp_owner, &public_key); - // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |_address| { // Bond the tokens, then unbond some of them @@ -530,14 +528,18 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &secret_key, + &[secret_key], + &pks_map, ))); + let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); let keys_changed: BTreeSet = @@ -565,6 +567,7 @@ mod tests { // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&vp_owner, &target, &token]); + tx_env.init_account_storage(&vp_owner, vec![public_key], 1); // Credit the tokens to the VP owner before running the transaction to // be able to transfer from it @@ -599,7 +602,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -624,8 +627,11 @@ mod tests { let token = address::nam(); let amount = token::Amount::from_uint(10_098_123, 0).unwrap(); + tx_env.init_parameters(None, None, None, None); + // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&vp_owner, &target, &token]); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Credit the tokens to the VP owner before running the transaction to // be able to transfer from it @@ -638,8 +644,6 @@ mod tests { ) .unwrap(); - tx_env.write_public_key(&vp_owner, &public_key); - let amount = token::DenominatedAmount { amount, denom: token::NATIVE_MAX_DECIMAL_PLACES.into(), @@ -660,20 +664,25 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &secret_key, + &[secret_key], + &pks_map, ))); + let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); let verifiers: BTreeSet
= BTreeSet::default(); vp_host_env::set(vp_env); + assert!( validate_tx(&CTX, signed_tx, vp_owner, keys_changed, verifiers) .unwrap() @@ -696,6 +705,7 @@ mod tests { // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&vp_owner, &source, &target, &token]); + tx_env.init_account_storage(&vp_owner, vec![public_key], 1); // Credit the tokens to the VP owner before running the transaction to // be able to transfer from it @@ -731,7 +741,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -760,8 +770,8 @@ mod tests { } proptest! { - /// Test that an unsigned tx that performs arbitrary storage writes or - /// deletes to the account is rejected. + /// Test that an unsigned tx that performs arbitrary storage writes + /// or deletes to the account is rejected. #[test] fn test_unsigned_arb_storage_write_rejected( (_sk, vp_owner, storage_key) in arb_account_storage_subspace_key(), @@ -787,7 +797,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -795,17 +805,12 @@ mod tests { vp_host_env::set(vp_env); assert!(!validate_tx(&CTX, tx_data, vp_owner, keys_changed, verifiers).unwrap()); } - } - proptest! { - /// Test that a signed tx that performs arbitrary storage writes or - /// deletes to the account is accepted. - #[test] - fn test_signed_arb_storage_write( - (secret_key, vp_owner, storage_key) in arb_account_storage_subspace_key(), - // Generate bytes to write. If `None`, delete from the key instead - storage_value in any::>>(), - ) { + fn test_signed_arb_storage_write( + (secret_key, vp_owner, storage_key) in arb_account_storage_subspace_key(), + // Generate bytes to write. If `None`, delete from the key instead + storage_value in any::>>(), + ) { // Initialize a tx environment let mut tx_env = TestTxEnv::default(); @@ -815,7 +820,7 @@ mod tests { tx_env.spawn_accounts(storage_key_addresses); let public_key = secret_key.ref_to(); - tx_env.write_public_key(&vp_owner, &public_key); + let _ = storage_api::account::set_public_key_at(tx_host_env::ctx(), &vp_owner, &public_key, 0); // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |_address| { @@ -827,11 +832,17 @@ mod tests { } }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new(vec![*tx.data_sechash(), *tx.code_sechash()], &secret_key))); + tx.add_section(Section::SectionSignature(MultiSignature::new( + vec![*tx.data_sechash(), *tx.code_sechash()], + &[secret_key], + &pks_map, + ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); let keys_changed: BTreeSet = @@ -869,7 +880,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -899,12 +910,12 @@ mod tests { None, Some(vec![vp_hash.to_string()]), Some(vec!["some_hash".to_string()]), + None, ); // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&vp_owner]); - - tx_env.write_public_key(&vp_owner, &public_key); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { @@ -914,13 +925,16 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &secret_key, + &[secret_key], + &pks_map, ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); @@ -947,13 +961,16 @@ mod tests { // for the update tx_env.store_wasm_code(vp_code); - let empty_sha256 = sha256(&[]).to_string(); - tx_env.init_parameters(None, None, Some(vec![empty_sha256])); + tx_env.init_parameters( + None, + Some(vec![vp_hash.to_string()]), + None, + None, + ); // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&vp_owner]); - - tx_env.write_public_key(&vp_owner, &public_key); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { @@ -963,13 +980,16 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_code(Code::new(vec![])); tx.set_data(Data::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &secret_key, + &[secret_key], + &pks_map, ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); diff --git a/wasm/wasm_source/src/vp_testnet_faucet.rs b/wasm/wasm_source/src/vp_testnet_faucet.rs index 5905c3cc4c..f41909f0c5 100644 --- a/wasm/wasm_source/src/vp_testnet_faucet.rs +++ b/wasm/wasm_source/src/vp_testnet_faucet.rs @@ -25,18 +25,8 @@ fn validate_tx( verifiers ); - let valid_sig = Lazy::new(|| { - let pk = key::get(ctx, &addr); - match pk { - Ok(Some(pk)) => tx_data - .verify_signature( - &pk, - &[*tx_data.data_sechash(), *tx_data.code_sechash()], - ) - .is_ok(), - _ => false, - } - }); + let valid_sig = + Lazy::new(|| verify_signatures(ctx, &tx_data, &addr).is_ok()); if !is_valid_tx(ctx, &tx_data)? { return reject(); @@ -117,7 +107,7 @@ fn validate_tx( #[cfg(test)] mod tests { use address::testing::arb_non_internal_address; - use namada::proto::{Code, Data, Signature}; + use namada::proto::{Code, Data, MultiSignature, Signature}; use namada::types::transaction::TxType; use namada_test_utils::TestWasms; // Use this as `#[test]` annotation to enable logging @@ -126,6 +116,7 @@ mod tests { use namada_tests::vp::vp_host_env::storage::Key; use namada_tests::vp::*; use namada_tx_prelude::{StorageWrite, TxEnv}; + use namada_vp_prelude::account::AccountPublicKeysMap; use namada_vp_prelude::key::RefTo; use proptest::prelude::*; use storage::testing::arb_account_storage_key_no_vp; @@ -138,7 +129,7 @@ mod tests { /// Test that no-op transaction (i.e. no storage modifications) accepted. #[test] fn test_no_op_transaction() { - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let addr: Address = address::testing::established_address_1(); let keys_changed: BTreeSet = BTreeSet::default(); @@ -192,7 +183,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -229,7 +220,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -258,8 +249,7 @@ mod tests { // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&vp_owner]); - - tx_env.write_public_key(&vp_owner, public_key); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { @@ -269,13 +259,16 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key.clone()]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &keypair, + &[keypair], + &pks_map, ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); @@ -341,7 +334,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -365,6 +358,7 @@ mod tests { let target = address::testing::established_address_2(); let target_key = key::testing::keypair_1(); + let _public_key = target_key.ref_to(); let token = address::nam(); let amount = token::Amount::from_uint(amount, 0).unwrap(); @@ -401,7 +395,7 @@ mod tests { let mut vp_env = vp_host_env::take(); // This is set by the protocol when the wrapper tx has a valid PoW vp_env.has_valid_pow = true; - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(solution_bytes)); tx_data.set_code(Code::new(vec![])); tx_data.add_section(Section::Signature(Signature::new(vec![*tx_data.data_sechash(), *tx_data.code_sechash()], &target_key))); @@ -436,7 +430,7 @@ mod tests { let storage_key_addresses = storage_key.find_addresses(); tx_env.spawn_accounts(storage_key_addresses); - tx_env.write_public_key(&vp_owner, public_key); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |_address| { @@ -448,11 +442,17 @@ mod tests { } }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key.clone()]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new(vec![*tx.data_sechash(), *tx.code_sechash()], &keypair))); + tx.add_section(Section::SectionSignature(MultiSignature::new( + vec![*tx.data_sechash(), *tx.code_sechash()], + &[keypair], + &pks_map, + ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); let keys_changed: BTreeSet = diff --git a/wasm/wasm_source/src/vp_user.rs b/wasm/wasm_source/src/vp_user.rs index 6d6977997e..d68801834a 100644 --- a/wasm/wasm_source/src/vp_user.rs +++ b/wasm/wasm_source/src/vp_user.rs @@ -28,8 +28,8 @@ impl<'a> From<&'a storage::Key> for KeyType<'a> { Self::Token { owner } } else if proof_of_stake::is_pos_key(key) { Self::PoS - } else if gov_storage::is_vote_key(key) { - let voter_address = gov_storage::get_voter_address(key); + } else if gov_storage::keys::is_vote_key(key) { + let voter_address = gov_storage::keys::get_voter_address(key); if let Some(address) = voter_address { Self::GovernanceVote(address) } else { @@ -60,18 +60,8 @@ fn validate_tx( verifiers ); - let valid_sig = Lazy::new(|| { - let pk = key::get(ctx, &addr); - match pk { - Ok(Some(pk)) => tx_data - .verify_signature( - &pk, - &[*tx_data.data_sechash(), *tx_data.code_sechash()], - ) - .is_ok(), - _ => false, - } - }); + let valid_sig = + Lazy::new(|| verify_signatures(ctx, &tx_data, &addr).is_ok()); if !is_valid_tx(ctx, &tx_data)? { return reject(); @@ -184,7 +174,7 @@ fn validate_tx( mod tests { use address::testing::arb_non_internal_address; use namada::ledger::pos::{GenesisValidator, PosParams}; - use namada::proto::{Code, Data, Signature}; + use namada::proto::{Code, Data, MultiSignature}; use namada::types::dec::Dec; use namada::types::storage::Epoch; use namada::types::transaction::TxType; @@ -196,6 +186,7 @@ mod tests { use namada_tests::vp::vp_host_env::storage::Key; use namada_tests::vp::*; use namada_tx_prelude::{StorageWrite, TxEnv}; + use namada_vp_prelude::account::AccountPublicKeysMap; use namada_vp_prelude::key::RefTo; use proptest::prelude::*; use storage::testing::arb_account_storage_key_no_vp; @@ -205,7 +196,7 @@ mod tests { /// Test that no-op transaction (i.e. no storage modifications) accepted. #[test] fn test_no_op_transaction() { - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let addr: Address = address::testing::established_address_1(); let keys_changed: BTreeSet = BTreeSet::default(); @@ -265,7 +256,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -323,7 +314,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -350,6 +341,7 @@ mod tests { // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&vp_owner, &target, &token]); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Credit the tokens to the VP owner before running the transaction to // be able to transfer from it @@ -362,8 +354,6 @@ mod tests { ) .unwrap(); - tx_env.write_public_key(&vp_owner, &public_key); - let amount = token::DenominatedAmount { amount, denom: token::NATIVE_MAX_DECIMAL_PLACES.into(), @@ -385,13 +375,16 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &keypair, + &[keypair], + &pks_map, ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); @@ -435,7 +428,7 @@ mod tests { let mut tx_env = tx_host_env::take(); let secret_key = key::testing::keypair_1(); - let _public_key = secret_key.ref_to(); + let public_key = secret_key.ref_to(); let vp_owner: Address = address::testing::established_address_2(); let target = address::testing::established_address_3(); let token = address::nam(); @@ -445,6 +438,7 @@ mod tests { // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&target, &token]); + tx_env.init_account_storage(&vp_owner, vec![public_key], 1); // write the denomination of NAM into storage storage_api::token::write_denom( &mut tx_env.wl_storage, @@ -469,7 +463,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -525,6 +519,8 @@ mod tests { // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&target, &token]); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); + // write the denomination of NAM into storage storage_api::token::write_denom( &mut tx_env.wl_storage, @@ -537,8 +533,6 @@ mod tests { // be able to transfer from it tx_env.credit_tokens(&vp_owner, &token, amount); - tx_env.write_public_key(&vp_owner, &public_key); - // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |_address| { // Bond the tokens, then unbond some of them @@ -550,13 +544,16 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &secret_key, + &[secret_key], + &pks_map, ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); @@ -612,7 +609,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -668,7 +665,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -697,8 +694,7 @@ mod tests { // their storage let storage_key_addresses = storage_key.find_addresses(); tx_env.spawn_accounts(storage_key_addresses); - - tx_env.write_public_key(&vp_owner, &public_key); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |_address| { @@ -710,11 +706,13 @@ mod tests { } }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_code(Code::new(vec![])); tx.set_data(Data::new(vec![])); - tx.add_section(Section::Signature(Signature::new(vec![*tx.data_sechash(), *tx.code_sechash()], &keypair))); + tx.add_section(Section::SectionSignature(MultiSignature::new(vec![*tx.data_sechash(), *tx.code_sechash()], &[keypair], &pks_map))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); let keys_changed: BTreeSet = @@ -750,7 +748,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); tx_data.set_code(Code::new(vec![])); let keys_changed: BTreeSet = @@ -769,7 +767,7 @@ mod tests { fn test_signed_vp_update_accepted() { // Initialize a tx environment let mut tx_env = TestTxEnv::default(); - tx_env.init_parameters(None, None, None); + tx_env.init_parameters(None, None, None, None); let vp_owner = address::testing::established_address_1(); let keypair = key::testing::keypair_1(); @@ -781,8 +779,7 @@ mod tests { // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&vp_owner]); - - tx_env.write_public_key(&vp_owner, &public_key); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { @@ -792,13 +789,16 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &keypair, + &[keypair], + &pks_map, ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); @@ -817,7 +817,12 @@ mod tests { fn test_signed_vp_update_not_whitelisted_rejected() { // Initialize a tx environment let mut tx_env = TestTxEnv::default(); - tx_env.init_parameters(None, Some(vec!["some_hash".to_string()]), None); + tx_env.init_parameters( + None, + Some(vec!["some_hash".to_string()]), + None, + None, + ); let vp_owner = address::testing::established_address_1(); let keypair = key::testing::keypair_1(); @@ -829,8 +834,7 @@ mod tests { // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&vp_owner]); - - tx_env.write_public_key(&vp_owner, &public_key); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { @@ -840,13 +844,16 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &keypair, + &[keypair], + &pks_map, ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); @@ -874,12 +881,16 @@ mod tests { // for the update tx_env.store_wasm_code(vp_code); - tx_env.init_parameters(None, Some(vec![vp_hash.to_string()]), None); + tx_env.init_parameters( + None, + Some(vec![vp_hash.to_string()]), + None, + None, + ); // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&vp_owner]); - - tx_env.write_public_key(&vp_owner, &public_key); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { @@ -889,13 +900,16 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &keypair, + &[keypair], + &pks_map, ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); @@ -927,12 +941,12 @@ mod tests { None, Some(vec![vp_hash.to_string()]), Some(vec!["some_hash".to_string()]), + None, ); // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&vp_owner]); - - tx_env.write_public_key(&vp_owner, &public_key); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { @@ -942,13 +956,16 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &keypair, + &[keypair], + &pks_map, ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); @@ -975,13 +992,17 @@ mod tests { // for the update tx_env.store_wasm_code(vp_code); - let empty_sha256 = sha256(&[]).to_string(); - tx_env.init_parameters(None, None, Some(vec![empty_sha256])); + // hardcoded hash of VP_ALWAYS_TRUE_WASM + tx_env.init_parameters( + None, + Some(vec![vp_hash.to_string()]), + None, + None, + ); // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&vp_owner]); - - tx_env.write_public_key(&vp_owner, &public_key); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { @@ -991,13 +1012,16 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_code(Code::new(vec![])); tx.set_data(Data::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &keypair, + &[keypair], + &pks_map, ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); diff --git a/wasm/wasm_source/src/vp_validator.rs b/wasm/wasm_source/src/vp_validator.rs index eb80929626..9b0de80f3e 100644 --- a/wasm/wasm_source/src/vp_validator.rs +++ b/wasm/wasm_source/src/vp_validator.rs @@ -30,8 +30,8 @@ impl<'a> From<&'a storage::Key> for KeyType<'a> { Self::Token { owner } } else if proof_of_stake::is_pos_key(key) { Self::PoS - } else if gov_storage::is_vote_key(key) { - let voter_address = gov_storage::get_voter_address(key); + } else if gov_storage::keys::is_vote_key(key) { + let voter_address = gov_storage::keys::get_voter_address(key); if let Some(address) = voter_address { Self::GovernanceVote(address) } else { @@ -60,18 +60,8 @@ fn validate_tx( verifiers ); - let valid_sig = Lazy::new(|| { - let pk = key::get(ctx, &addr); - match pk { - Ok(Some(pk)) => tx_data - .verify_signature( - &pk, - &[*tx_data.data_sechash(), *tx_data.code_sechash()], - ) - .is_ok(), - _ => false, - } - }); + let valid_sig = + Lazy::new(|| verify_signatures(ctx, &tx_data, &addr).is_ok()); if !is_valid_tx(ctx, &tx_data)? { return reject(); @@ -191,7 +181,7 @@ fn validate_tx( mod tests { use address::testing::arb_non_internal_address; use namada::ledger::pos::{GenesisValidator, PosParams}; - use namada::proto::{Code, Data, Signature}; + use namada::proto::{Code, Data, MultiSignature}; use namada::types::dec::Dec; use namada::types::storage::Epoch; use namada::types::transaction::TxType; @@ -203,6 +193,7 @@ mod tests { use namada_tests::vp::vp_host_env::storage::Key; use namada_tests::vp::*; use namada_tx_prelude::{StorageWrite, TxEnv}; + use namada_vp_prelude::account::AccountPublicKeysMap; use namada_vp_prelude::key::RefTo; use proptest::prelude::*; use storage::testing::arb_account_storage_key_no_vp; @@ -212,7 +203,7 @@ mod tests { /// Test that no-op transaction (i.e. no storage modifications) accepted. #[test] fn test_no_op_transaction() { - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let addr: Address = address::testing::established_address_1(); let keys_changed: BTreeSet = BTreeSet::default(); @@ -272,7 +263,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -330,7 +321,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -357,6 +348,7 @@ mod tests { // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&vp_owner, &target, &token]); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Credit the tokens to the VP owner before running the transaction to // be able to transfer from it @@ -369,7 +361,6 @@ mod tests { ) .unwrap(); - tx_env.write_public_key(&vp_owner, &public_key); let amount = token::DenominatedAmount { amount, denom: token::NATIVE_MAX_DECIMAL_PLACES.into(), @@ -391,13 +382,16 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &keypair, + &[keypair], + &pks_map, ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); @@ -441,7 +435,7 @@ mod tests { let mut tx_env = tx_host_env::take(); let secret_key = key::testing::keypair_1(); - let _public_key = secret_key.ref_to(); + let public_key = secret_key.ref_to(); let vp_owner: Address = address::testing::established_address_2(); let target = address::testing::established_address_3(); let token = address::nam(); @@ -451,6 +445,7 @@ mod tests { // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&target, &token]); + tx_env.init_account_storage(&vp_owner, vec![public_key], 1); // Credit the tokens to the VP owner before running the transaction to // be able to transfer from it @@ -481,7 +476,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -536,7 +531,8 @@ mod tests { let unbond_amount = token::Amount::from_uint(3_098_123, 0).unwrap(); // Spawn the accounts to be able to modify their storage - tx_env.spawn_accounts([&target, &token]); + tx_env.spawn_accounts([&vp_owner, &target, &token]); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Credit the tokens to the VP owner before running the transaction to // be able to transfer from it @@ -549,8 +545,6 @@ mod tests { ) .unwrap(); - tx_env.write_public_key(&vp_owner, &public_key); - // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |_address| { // Bond the tokens, then unbond some of them @@ -568,13 +562,16 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &secret_key, + &[secret_key], + &pks_map, ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); @@ -629,7 +626,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -685,7 +682,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -715,7 +712,7 @@ mod tests { let storage_key_addresses = storage_key.find_addresses(); tx_env.spawn_accounts(storage_key_addresses); - tx_env.write_public_key(&vp_owner, &public_key); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |_address| { @@ -727,11 +724,13 @@ mod tests { } }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new(vec![*tx.data_sechash(), *tx.code_sechash()], &keypair))); + tx.add_section(Section::SectionSignature(MultiSignature::new(vec![*tx.data_sechash(), *tx.code_sechash()], &[keypair], &pks_map))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); let keys_changed: BTreeSet = @@ -767,7 +766,7 @@ mod tests { }); let vp_env = vp_host_env::take(); - let mut tx_data = Tx::new(TxType::Raw); + let mut tx_data = Tx::from_type(TxType::Raw); tx_data.set_data(Data::new(vec![])); let keys_changed: BTreeSet = vp_env.all_touched_storage_keys(); @@ -785,7 +784,7 @@ mod tests { fn test_signed_vp_update_accepted() { // Initialize a tx environment let mut tx_env = TestTxEnv::default(); - tx_env.init_parameters(None, None, None); + tx_env.init_parameters(None, None, None, None); let vp_owner = address::testing::established_address_1(); let keypair = key::testing::keypair_1(); @@ -797,8 +796,7 @@ mod tests { // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&vp_owner]); - - tx_env.write_public_key(&vp_owner, &public_key); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { @@ -808,13 +806,16 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &keypair, + &[keypair], + &pks_map, ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); @@ -833,7 +834,12 @@ mod tests { fn test_signed_vp_update_not_whitelisted_rejected() { // Initialize a tx environment let mut tx_env = TestTxEnv::default(); - tx_env.init_parameters(None, Some(vec!["some_hash".to_string()]), None); + tx_env.init_parameters( + None, + Some(vec!["some_hash".to_string()]), + None, + None, + ); let vp_owner = address::testing::established_address_1(); let keypair = key::testing::keypair_1(); @@ -845,8 +851,7 @@ mod tests { // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&vp_owner]); - - tx_env.write_public_key(&vp_owner, &public_key); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { @@ -856,13 +861,16 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &keypair, + &[keypair], + &pks_map, ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); @@ -890,12 +898,16 @@ mod tests { // for the update tx_env.store_wasm_code(vp_code); - tx_env.init_parameters(None, Some(vec![vp_hash.to_string()]), None); + tx_env.init_parameters( + None, + Some(vec![vp_hash.to_string()]), + None, + None, + ); // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&vp_owner]); - - tx_env.write_public_key(&vp_owner, &public_key); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { @@ -905,13 +917,16 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &keypair, + &[keypair], + &pks_map, ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); @@ -943,12 +958,12 @@ mod tests { None, Some(vec![vp_hash.to_string()]), Some(vec!["some_hash".to_string()]), + None, ); // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&vp_owner]); - - tx_env.write_public_key(&vp_owner, &public_key); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { @@ -958,13 +973,16 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_data(Data::new(vec![])); tx.set_code(Code::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &keypair, + &[keypair], + &pks_map, ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); @@ -991,13 +1009,17 @@ mod tests { // for the update tx_env.store_wasm_code(vp_code); - let empty_sha256 = sha256(&[]).to_string(); - tx_env.init_parameters(None, None, Some(vec![empty_sha256])); + // hardcoded hash of VP_ALWAYS_TRUE_WASM + tx_env.init_parameters( + None, + Some(vec![vp_hash.to_string()]), + None, + None, + ); // Spawn the accounts to be able to modify their storage tx_env.spawn_accounts([&vp_owner]); - - tx_env.write_public_key(&vp_owner, &public_key); + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); // Initialize VP environment from a transaction vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { @@ -1007,13 +1029,16 @@ mod tests { .unwrap(); }); + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + let mut vp_env = vp_host_env::take(); let mut tx = vp_env.tx.clone(); tx.set_code(Code::new(vec![])); tx.set_data(Data::new(vec![])); - tx.add_section(Section::Signature(Signature::new( + tx.add_section(Section::SectionSignature(MultiSignature::new( vec![*tx.data_sechash(), *tx.code_sechash()], - &keypair, + &[keypair], + &pks_map, ))); let signed_tx = tx.clone(); vp_env.tx = signed_tx.clone(); diff --git a/wasm_for_tests/tx_memory_limit.wasm b/wasm_for_tests/tx_memory_limit.wasm index 3f8ae1b079f1c308d4c96f03d7a1f3fb5f9d78b0..a6e413f349827e539fe5da233ceb71ffee891f13 100755 GIT binary patch delta 142043 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%0A(^rLytG9}> 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 delta 132096 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 diff --git a/wasm_for_tests/tx_mint_tokens.wasm b/wasm_for_tests/tx_mint_tokens.wasm index dba64ff70a1fe3ab7c081371f2baebc267fa7d3b..416ab231ace7a51746d3945abf0f1b19ccce11fb 100755 GIT binary patch delta 121366 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 EKWcfk0ssI2 delta 123598 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 delta 103423 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 z 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 OJ#95wPX})L+WU diff --git a/wasm_for_tests/tx_proposal_code.wasm b/wasm_for_tests/tx_proposal_code.wasm index 3c937a2eccfdf961d166e8264c443932bc24c734..89bab50905416274cfc472bc7bc9f062817812e3 100755 GIT binary patch delta 140094 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%0AA4f72x!*gPFgM0{E=?8pozmC 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�)E26q}WXZO|&sbK5Lr7>r zb3zirV#FSADIbz_1G+%A3wDbj)5GxKf^Cjo;E<|YV0(ss6x&W48L7w7;F0O$3ZiU@N=w-5h%kgd>v&T;gXOH&dS4Z}2vq$?u{P{iG z-_LuZd$c`sqb?jtFPV!kyiu20rCfcZuARN-N|ENp)~03Z5b&Iar3-T5wQwR<%(-1k zWl5banWI<6FzB!?r(PD}RXX1^7Wc&$Fk-Ccx@iFerusl|XF}K<5a< zDOxh`lrudrQF_;iG@k5?L9#Pft~Qp4uuey1vN>x`sjVzl1r!BNF5hG|Ix^0eH2dv@~icok(Zq8q7N!G+{V|_y^>~hMz zPC-}5bxzt@Y(6z%1eCERA+ODKaKH%^Wpt{t?B>9W*e0B@Gw?R*o|Vko0ZP8x1dr>2 zXbct_ubYuN1w=WNCsHWdWcjmJ`3G$CD*u&bUj(h%dYuKv(ZnFg&DC@)(zAXKTW)?E zj!-3RTBMdjyP$`;#lX*Il)S4h?<&u`!d3^1C~>iduMohHs{=_?U;UcX%>+(@yPC+B zz_{38M5vY~K$QJVqk_g{0DTUS_v1Ueu^%fJrd7-s6SP(*>iKpMpi|5dH4ve^3E_~z z#lV|*Aj=C@W51FdW6ccfeq0bP!@7y8g5ewshBHHDXT!N89t>weG$ttXf+wY;g)^!x zWfzX)ChBIGH<@9sNA>0$hzIy^h-BAeyQQ%B?3RFa$iei2$_0a&ktB+YTTx(SkVeLB zsOLn+?KV=$AdQUMtx~@nDv1nSp#|9tS~zeS1okto84wVkR(Fifv6)ag^d1>|99IwS zGuFckU-&2!!vtTK=8{{6w`ΝR}@<7!AIWA#;+ED2hv~00HaxM82pLTLb_5^3AY! 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 delta 149140 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

8%OcoWP5igzT6`e388P7TDJ4Ar{jpdb^ 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 diff --git a/wasm_for_tests/tx_write.wasm b/wasm_for_tests/tx_write.wasm index edd28f97ecf2866e4b5e7160898fc7c00bf96b00..46ae3e95a00abd4417d5e67fd01656bb40770a35 100755 GIT binary patch delta 126799 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�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/x9rv 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 P+&It2L-Tx5Kfm^Gg_fWx diff --git a/wasm_for_tests/vp_always_false.wasm b/wasm_for_tests/vp_always_false.wasm index 992f4007a741e6b6ce2f397cad55d98fcf44cb08..7fa0714a4ed2015739750b4beccaf2ea3a50f66c 100755 GIT binary patch delta 149049 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 W=_gaBB9SxF2x?Dt4jO69^8G(FyZyZY delta 140573 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%0D9ZnI{HKLGEeEi4k#nb>|r~^ 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 Yt-3_h6y-coI}?l4#@4%LYBOB_A5(ntEdT%j diff --git a/wasm_for_tests/vp_eval.wasm b/wasm_for_tests/vp_eval.wasm index 2ed4af1c95975381e8a56966d6b04b917210845f..7ceeef5c810ada1204f721605fb8d850e5c41c47 100755 GIT binary patch literal 492706 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�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�sb_`WpA2#_jUk78NRV2<8=;sujmK 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

!Kr4Hl0Q^>mzbmh$lpoT|5uwZ5Br z-GoaQs`yqSFrM=KXaq+lrA9#~KyiE-afpR@#j#3+%WF8LD2xQ;1wz3XqmSG$Y7X`; z097XM(uy09cP6@4I+fC?Moz6lC+>RwNmbJUduo=U2Jh3=`>0RR>r#m+G4vB~1iJ{I z9g%hTP%tj5*xPH!iWF+eht8#BRwFcgD@PPO%S+;D4)lZFn?t9>Y5JyajAEKHdoe0| zF>|=WqJBMdh@wTyL72=D3O|Ca2lB?lknSbu?n2x)W?k!mL$nCYM_>-*5(SbXNV%b^ z#oH*?%SZqkI2q_ZNl?Uw_3~=vk4UHcYn2Xq$_kYY@|B8F{zR|D39KG6f&NqHL;NF5 z`c~^hE$;A63fEA2J&X5>*hCQ+D4SWmw^u}m8Nr@r^=hw(wTLjbV(LQ!=mTBorZe%@ ziaCrTu*^Ru*~Rs3ip-# zR8mcCQ|lSx+bEut1iDSrBuBTrd=4;@hLOt*T?RQ4R}nzLkiY{KLF-Abf(V;WMSo!Gm5_s3hk#X4Rf~f$oi4q_vGFCopws7Uc z%0A+-)Oml;hHMY!>F=Q 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 ~*@A1CFc;jbm- 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⪻U>OtQZRJlBaeDs{+XPg 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 M%i|a8jIG9h0q8IB`Tzg` diff --git a/wasm_for_tests/vp_read_storage_key.wasm b/wasm_for_tests/vp_read_storage_key.wasm index 202f5bf008463011375c2c4c09da88e846aa094d..3e21d22cb2a7619f030c6455d76d50ff70824a01 100755 GIT binary patch literal 475686 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

`GSEkcoxNaMWqC7CVW}fd^7v98?QCfxMmOn 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%0DR6XG5}u&g62E5|YOjd#nIbrZ|FDK4wP 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%0Ak+)|Hzs%k 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 z⁣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 TxResult { // governance - let target_key = gov_storage::get_min_proposal_grace_epoch_key(); + let target_key = gov_storage::keys::get_min_proposal_grace_epoch_key(); ctx.write(&target_key, 9_u64)?; // parameters @@ -127,30 +127,6 @@ pub mod main { } } -/// A tx that attempts to mint tokens in the transfer's target without debiting -/// the tokens from the source. This tx is expected to be rejected by the -/// token's VP. -#[cfg(feature = "tx_mint_tokens")] -pub mod main { - use namada_test_utils::tx_data::TxMintData; - use namada_tx_prelude::*; - - #[transaction] - fn apply_tx(ctx: &mut Ctx, tx_data: Tx) -> TxResult { - let signed = tx_data; - let mint_data = - TxMintData::try_from_slice(&signed.data().unwrap()[..]).unwrap(); - log_string(format!("apply_tx called to mint tokens: {:#?}", mint_data)); - let TxMintData { - minter, - target, - token, - amount, - } = mint_data; - token::mint(ctx, &minter, &target, &token, amount) - } -} - /// A VP that always returns `true`. #[cfg(feature = "vp_always_true")] pub mod main {