Skip to content

Commit

Permalink
Merge branch 'grarco/tx-batch' (#3103)
Browse files Browse the repository at this point in the history
* grarco/tx-batch:
  Restores `batch_size` arg for `fetch`
  Refactors `dispatch_tx` to return a result
  Refactors masp events to avoid dynamic attributes
  Short-circuit atomic batches at the first failure
  Implements a `get_tx_data` method on `Ctx`
  Refactors validity booleans into a `ValidityFlags` struct
  Refactors buckets in write log with iterator chains
  Misc refactors, fixes typo
  Improves unit tests for batches
  Refactors match on inner tx result
  Preserve txs order when constructing batch in the sdk
  Drops duplicated events for errored batch
  More unit tests for tx batching
  Appends inner tx result even in case of out of gas
  Better handling of batch errors
  Restores shielded sync struct in the sdk
  Reverts wrong shielded sync cli changes
  Removes broken batch section optimization
  Extracts ok tx result evaluation to a separate function
  Changes error code for batches. Fixes missing events
  Refactors `evaluate_tx_result`. Updates stats
  Renames `TxInfo` and fixes write log commit in `finalize_block`
  Refactors stats accounting
  Reverts `TryFrom` impls for ethereum data to `Tx`
  Changelog #1356
  Adds unit tests for tx batches
  Updates tx types comparisons and avoid duplicated signatures for batches
  Updates error message in ibc test
  Fixes bug in wrapper keys
  Fixes fee payemnt logic and unit tests
  Recomputes signatures for localnet genesis
  Clippy fix
  Removes unused `Ciphertext` section
  Updates `add_inner_tx` to avoid duplicated sections
  Adds new `mk_tx_batch` for unit testing
  Fixes tx interface to attach a new inner tx
  Updates comments
  Adds an SDK function to construct tx batches
  Renames `Commitments` and update docs
  Refactors the batch write log
  Refactors tx result handling in `finalize_block`
  Removes custom borsh impls for `BatchedTx` and `BatchedTxRef`
  More refactoring
  Misc refactoring
  Fixes benchmarks
  Fixes integration tests
  Fixes wasm tests
  Refactors test envs
  Fixes serialization of tx result and unit tests
  Rebuilds wasm for tests
  Recomputes genesis signatures. Fixes missing commitments in tests
  Updates `VpEval`
  Fixes wasm for test. Clippy + fmt
  Updates wasm interface and codes
  Renames batched txs structs
  Misc updates to write log. Updates tx result handling in `finalize_block`
  Updates `WriteLog` to support tx batches
  Improves handling of txs' results in `dispatch_tx` and `finalize_block`
  Introduces `OwnedBatchedTx` for benchmarks. Fixes benches and tests
  Generic `TxResult`
  Updates contexts for batched transactions. Misc updates to protocol
  Updates logs and tx result to support batching
  Adds `BatchedTx` struct and updated the native vps and transactions execution
  Updates core tx methods and masp client functions
  Adds multiple tx commitments in `Header`
  • Loading branch information
brentstone committed May 16, 2024
2 parents 9da7e5d + 97a2d8d commit ad7f921
Show file tree
Hide file tree
Showing 143 changed files with 4,248 additions and 12,381 deletions.
2 changes: 2 additions & 0 deletions .changelog/unreleased/features/1356-tx-batch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Introduced transaction batches.
([\#1356](https://github.com/anoma/namada/pull/1356))
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 60 additions & 26 deletions crates/apps/src/lib/bench_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use namada::core::masp::{
use namada::core::storage::{BlockHeight, Epoch, Key, KeySeg, TxIndex};
use namada::core::time::DateTimeUtc;
use namada::core::token::{Amount, DenominatedAmount, Transfer};
use namada::events::extend::{ComposeEvent, ValidMaspTx};
use namada::events::extend::{ComposeEvent, MaspTxBatchRefs, MaspTxBlockIndex};
use namada::events::Event;
use namada::governance::storage::proposal::ProposalType;
use namada::governance::InitProposalData;
Expand Down Expand Up @@ -76,9 +76,13 @@ use namada::ledger::queries::{
};
use namada::state::StorageRead;
use namada::tx::data::pos::Bond;
use namada::tx::data::{Fee, TxResult, VpsResult};
use namada::tx::event::{new_tx_event, InnerTx};
use namada::tx::{Authorization, Code, Data, Section, Tx};
use namada::tx::data::{
BatchResults, BatchedTxResult, Fee, TxResult, VpsResult,
};
use namada::tx::event::{new_tx_event, Batch};
use namada::tx::{
Authorization, BatchedTx, BatchedTxRef, Code, Data, Section, Tx,
};
use namada::vm::wasm::run;
use namada::{proof_of_stake, tendermint};
use namada_sdk::masp::{
Expand Down Expand Up @@ -242,7 +246,7 @@ impl Default for BenchShell {
vec![&defaults::albert_keypair()],
);

bench_shell.execute_tx(&signed_tx);
bench_shell.execute_tx(&signed_tx.to_ref());
bench_shell.state.commit_tx();

// Initialize governance proposal
Expand All @@ -267,7 +271,7 @@ impl Default for BenchShell {
vec![&defaults::albert_keypair()],
);

bench_shell.execute_tx(&signed_tx);
bench_shell.execute_tx(&signed_tx.to_ref());
bench_shell.state.commit_tx();
bench_shell.commit_block();

Expand All @@ -293,7 +297,7 @@ impl BenchShell {
shielded: Option<Transaction>,
extra_sections: Option<Vec<Section>>,
signers: Vec<&SecretKey>,
) -> Tx {
) -> BatchedTx {
let mut tx = Tx::from_type(namada::tx::data::TxType::Raw);

// NOTE: here we use the code hash to avoid including the cost for the
Expand Down Expand Up @@ -329,10 +333,15 @@ impl BenchShell {
)));
}

tx
let cmt = tx.first_commitments().unwrap().clone();
tx.batch_tx(cmt)
}

pub fn generate_ibc_tx(&self, wasm_code_path: &str, data: Vec<u8>) -> Tx {
pub fn generate_ibc_tx(
&self,
wasm_code_path: &str,
data: Vec<u8>,
) -> BatchedTx {
// This function avoid serializaing the tx data with Borsh
let mut tx = Tx::from_type(namada::tx::data::TxType::Raw);
let code_hash = self
Expand All @@ -345,10 +354,11 @@ impl BenchShell {

tx.set_data(Data::new(data));
// NOTE: the Ibc VP doesn't actually check the signature
tx
let cmt = tx.first_commitments().unwrap().clone();
tx.batch_tx(cmt)
}

pub fn generate_ibc_transfer_tx(&self) -> Tx {
pub fn generate_ibc_transfer_tx(&self) -> BatchedTx {
let token = PrefixedCoin {
denom: address::testing::nam().to_string().parse().unwrap(),
amount: Amount::native_whole(1000)
Expand Down Expand Up @@ -392,14 +402,18 @@ impl BenchShell {
}

/// Execute the tx and return a set of verifiers inserted by the tx.
pub fn execute_tx(&mut self, tx: &Tx) -> BTreeSet<Address> {
pub fn execute_tx(
&mut self,
batched_tx: &BatchedTxRef,
) -> BTreeSet<Address> {
let gas_meter =
RefCell::new(TxGasMeter::new_from_sub_limit(u64::MAX.into()));
run::tx(
&mut self.inner.state,
&gas_meter,
&TxIndex(0),
tx,
batched_tx.tx,
batched_tx.cmt,
&mut self.inner.vp_wasm_cache,
&mut self.inner.tx_wasm_cache,
)
Expand Down Expand Up @@ -605,7 +619,7 @@ impl BenchShell {
}
}

pub fn generate_foreign_key_tx(signer: &SecretKey) -> Tx {
pub fn generate_foreign_key_tx(signer: &SecretKey) -> BatchedTx {
let wasm_code =
std::fs::read("../../wasm_for_tests/tx_write.wasm").unwrap();

Expand All @@ -624,7 +638,8 @@ pub fn generate_foreign_key_tx(signer: &SecretKey) -> Tx {
None,
)));

tx
let cmt = tx.first_commitments().unwrap().clone();
tx.batch_tx(cmt)
}

pub struct BenchShieldedCtx {
Expand Down Expand Up @@ -887,17 +902,34 @@ impl Client for BenchShell {
.iter()
.enumerate()
.map(|(idx, (tx, changed_keys))| {
let tx_result = TxResult {
let tx_result = TxResult::<String> {
gas_used: 0.into(),
wrapper_changed_keys: Default::default(),
changed_keys: changed_keys.to_owned(),
vps_result: VpsResult::default(),
initialized_accounts: vec![],
events: BTreeSet::default(),
batch_results: BatchResults(
[(
tx.first_commitments().unwrap().get_hash(),
Ok(BatchedTxResult {
changed_keys: changed_keys.to_owned(),
vps_result: VpsResult::default(),
initialized_accounts: vec![],
events: BTreeSet::default(),
}),
)]
.into_iter()
.collect(),
),
};
let event: Event = new_tx_event(tx, height.value())
.with(InnerTx(&tx_result))
.with(ValidMaspTx(TxIndex::must_from_usize(idx)))
.with(Batch(&tx_result))
.with(MaspTxBlockIndex(TxIndex::must_from_usize(
idx,
)))
.with(MaspTxBatchRefs(
vec![
tx.first_commitments().unwrap().get_hash(),
]
.into(),
))
.into();
namada::tendermint::abci::Event::from(event)
})
Expand Down Expand Up @@ -1007,7 +1039,7 @@ impl BenchShieldedCtx {
amount: Amount,
source: TransferSource,
target: TransferTarget,
) -> (Self, Tx) {
) -> (Self, BatchedTx) {
let denominated_amount = DenominatedAmount::native(amount);
let async_runtime = tokio::runtime::Runtime::new().unwrap();
let spending_key = self
Expand Down Expand Up @@ -1103,7 +1135,7 @@ impl BenchShieldedCtx {
amount: Amount,
source: TransferSource,
target: TransferTarget,
) -> (Self, Tx) {
) -> (Self, BatchedTx) {
let (ctx, tx) = self.generate_masp_tx(
amount,
source.clone(),
Expand Down Expand Up @@ -1143,8 +1175,10 @@ impl BenchShieldedCtx {
};

let transfer =
Transfer::deserialize(&mut tx.data().unwrap().as_slice()).unwrap();
Transfer::deserialize(&mut tx.tx.data(&tx.cmt).unwrap().as_slice())
.unwrap();
let masp_tx = tx
.tx
.get_section(&transfer.shielded.unwrap())
.unwrap()
.masp_tx()
Expand All @@ -1157,7 +1191,7 @@ impl BenchShieldedCtx {
let mut ibc_tx = ctx
.shell
.generate_ibc_tx(TX_IBC_WASM, msg.serialize_to_vec());
ibc_tx.add_masp_tx_section(masp_tx);
ibc_tx.tx.add_masp_tx_section(masp_tx);

(ctx, ibc_tx)
}
Expand Down
4 changes: 2 additions & 2 deletions crates/apps/src/lib/client/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use namada_sdk::rpc::{
self, enriched_bonds_and_unbonds, query_epoch, TxResponse,
};
use namada_sdk::tendermint_rpc::endpoint::status;
use namada_sdk::tx::display_inner_resp;
use namada_sdk::tx::display_batch_resp;
use namada_sdk::wallet::AddressVpType;
use namada_sdk::{display, display_line, edisplay_line, error, Namada};

Expand Down Expand Up @@ -1898,7 +1898,7 @@ pub async fn query_result(context: &impl Namada, args: args::QueryResult) {
cli::safe_exit(1)
}
};
display_inner_resp(context, &resp);
display_batch_resp(context, &resp);
}
Err(err) => {
// Print the errors that caused the lookups to fail
Expand Down
15 changes: 10 additions & 5 deletions crates/apps/src/lib/client/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,8 +299,9 @@ where
} else {
sign(namada, &mut tx, &args.tx, signing_data).await?;

let cmt = tx.first_commitments().unwrap().to_owned();
let response = namada.submit(tx, &args.tx).await?;
if let Some(result) = response.is_applied_and_valid() {
if let Some(result) = response.is_applied_and_valid(&cmt) {
return Ok(result.initialized_accounts.first().cloned());
}
}
Expand Down Expand Up @@ -377,10 +378,11 @@ pub async fn submit_change_consensus_key(
tx::dump_tx(namada.io(), &args.tx, tx);
} else {
sign(namada, &mut tx, &args.tx, signing_data).await?;
let cmt = tx.first_commitments().unwrap().to_owned();
let resp = namada.submit(tx, &args.tx).await?;

if !args.tx.dry_run {
if resp.is_applied_and_valid().is_some() {
if resp.is_applied_and_valid(&cmt).is_some() {
namada.wallet_mut().await.save().unwrap_or_else(|err| {
edisplay_line!(namada.io(), "{}", err)
});
Expand Down Expand Up @@ -570,6 +572,7 @@ pub async fn submit_become_validator(
tx::dump_tx(namada.io(), &args.tx, tx);
} else {
sign(namada, &mut tx, &args.tx, signing_data).await?;
let cmt = tx.first_commitments().unwrap().to_owned();
let resp = namada.submit(tx, &args.tx).await?;

if args.tx.dry_run {
Expand All @@ -580,7 +583,7 @@ pub async fn submit_become_validator(
safe_exit(0)
}

if resp.is_applied_and_valid().is_none() {
if resp.is_applied_and_valid(&cmt).is_none() {
display_line!(
namada.io(),
"Transaction failed. No key or addresses have been saved."
Expand Down Expand Up @@ -758,6 +761,7 @@ pub async fn submit_transfer(
break;
} else {
sign(namada, &mut tx, &args.tx, signing_data).await?;
let cmt_hash = tx.first_commitments().unwrap().get_hash();

let result = namada.submit(tx, &args.tx).await?;

Expand All @@ -766,7 +770,7 @@ pub async fn submit_transfer(
// If a transaction is shielded
tx_epoch.is_some() &&
// And it is rejected by a VP
matches!(resp.inner_tx_result(), InnerTxResult::VpsRejected(_)) =>
matches!(resp.batch_result().get(&cmt_hash), Some(InnerTxResult::VpsRejected(_))) =>
{
let submission_epoch = rpc::query_and_print_epoch(namada).await;
// And its submission epoch doesn't match construction epoch
Expand Down Expand Up @@ -1067,9 +1071,10 @@ where
tx::dump_tx(namada.io(), &args.tx, tx);
} else {
sign(namada, &mut tx, &args.tx, signing_data).await?;
let cmt = tx.first_commitments().unwrap().to_owned();
let resp = namada.submit(tx, &args.tx).await?;

if !args.tx.dry_run && resp.is_applied_and_valid().is_some() {
if !args.tx.dry_run && resp.is_applied_and_valid(&cmt).is_some() {
tx::query_unbonds(namada, args.clone(), latest_withdrawal_pre)
.await?;
}
Expand Down
Loading

0 comments on commit ad7f921

Please sign in to comment.