Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tx batching #3103

Merged
merged 68 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from 61 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
ac39259
Adds multiple tx commitments in `Header`
grarco Apr 5, 2024
086a8a8
Updates core tx methods and masp client functions
grarco Apr 15, 2024
9bfed1c
Adds `BatchedTx` struct and updated the native vps and transactions e…
grarco Apr 17, 2024
50518ea
Updates logs and tx result to support batching
grarco Apr 19, 2024
167204f
Updates contexts for batched transactions. Misc updates to protocol
grarco Apr 21, 2024
1da5b0a
Generic `TxResult`
grarco Apr 21, 2024
5853fb1
Introduces `OwnedBatchedTx` for benchmarks. Fixes benches and tests
grarco Apr 21, 2024
6374f1a
Improves handling of txs' results in `dispatch_tx` and `finalize_block`
grarco Apr 22, 2024
3a846bd
Updates `WriteLog` to support tx batches
grarco Apr 23, 2024
8fdea42
Misc updates to write log. Updates tx result handling in `finalize_bl…
grarco Apr 24, 2024
7267a43
Renames batched txs structs
grarco Apr 26, 2024
da34ab9
Updates wasm interface and codes
grarco Apr 26, 2024
af4513d
Fixes wasm for test. Clippy + fmt
grarco Apr 26, 2024
eace62f
Updates `VpEval`
grarco Apr 26, 2024
c4d19fa
Recomputes genesis signatures. Fixes missing commitments in tests
grarco Apr 28, 2024
b4176e9
Rebuilds wasm for tests
grarco Apr 28, 2024
55dae06
Fixes serialization of tx result and unit tests
grarco Apr 28, 2024
2fd7f4c
Refactors test envs
grarco Apr 28, 2024
b342781
Fixes wasm tests
grarco Apr 28, 2024
aaf26c4
Fixes integration tests
grarco Apr 29, 2024
07ec96e
Fixes benchmarks
grarco Apr 29, 2024
baac8ec
Misc refactoring
grarco Apr 29, 2024
593be95
More refactoring
grarco Apr 30, 2024
a50b4d8
Removes custom borsh impls for `BatchedTx` and `BatchedTxRef`
grarco Apr 30, 2024
25bb28c
Refactors tx result handling in `finalize_block`
grarco Apr 30, 2024
dc364c6
Refactors the batch write log
grarco Apr 30, 2024
db3e688
Renames `Commitments` and update docs
grarco Apr 30, 2024
4d0d34e
Adds an SDK function to construct tx batches
grarco Apr 30, 2024
3ec07af
Updates comments
grarco Apr 30, 2024
39ae3e9
Fixes tx interface to attach a new inner tx
grarco Apr 30, 2024
fedccfa
Adds new `mk_tx_batch` for unit testing
grarco Apr 30, 2024
74d11f8
Updates `add_inner_tx` to avoid duplicated sections
grarco May 1, 2024
245c702
Removes unused `Ciphertext` section
grarco May 1, 2024
0798717
Merge branch 'v0.34.0' into grarco/tx-batch
grarco May 1, 2024
2a55ca4
Clippy fix
grarco May 1, 2024
709de20
Recomputes signatures for localnet genesis
grarco May 1, 2024
6665cb1
Fixes fee payemnt logic and unit tests
grarco May 1, 2024
502efc5
Fixes bug in wrapper keys
grarco May 2, 2024
32d2888
Merge branch 'base' into grarco/tx-batch
grarco May 2, 2024
f6448d3
Updates error message in ibc test
grarco May 2, 2024
704ce45
Updates tx types comparisons and avoid duplicated signatures for batches
grarco May 2, 2024
e8090ed
Adds unit tests for tx batches
grarco May 2, 2024
08c93e4
Changelog #1356
grarco May 2, 2024
c918b37
Reverts `TryFrom` impls for ethereum data to `Tx`
grarco May 3, 2024
77326c7
Refactors stats accounting
grarco May 3, 2024
4be5dbc
Renames `TxInfo` and fixes write log commit in `finalize_block`
grarco May 4, 2024
6b1a5e1
Refactors `evaluate_tx_result`. Updates stats
grarco May 4, 2024
047a00d
Changes error code for batches. Fixes missing events
grarco May 5, 2024
2bd903d
Extracts ok tx result evaluation to a separate function
grarco May 5, 2024
d5c50c9
Removes broken batch section optimization
grarco May 6, 2024
93376c7
Reverts wrong shielded sync cli changes
grarco May 6, 2024
d5b4bb5
Restores shielded sync struct in the sdk
grarco May 6, 2024
cfb6cc3
Better handling of batch errors
grarco May 6, 2024
86515cf
Appends inner tx result even in case of out of gas
grarco May 6, 2024
c4410f2
More unit tests for tx batching
grarco May 6, 2024
678f029
Drops duplicated events for errored batch
grarco May 6, 2024
47ccfd3
Preserve txs order when constructing batch in the sdk
grarco May 7, 2024
7874576
Refactors match on inner tx result
grarco May 7, 2024
c1e7f7e
Improves unit tests for batches
grarco May 7, 2024
7b26560
Misc refactors, fixes typo
grarco May 7, 2024
9422864
Refactors buckets in write log with iterator chains
grarco May 7, 2024
525d044
Refactors validity booleans into a `ValidityFlags` struct
grarco May 7, 2024
0a40071
Implements a `get_tx_data` method on `Ctx`
grarco May 7, 2024
8ab0f38
Short-circuit atomic batches at the first failure
grarco May 7, 2024
01510ea
Refactors masp events to avoid dynamic attributes
grarco May 8, 2024
db8fa36
Refactors `dispatch_tx` to return a result
grarco May 8, 2024
7f4b6c1
Merge branch 'v0.35.1' into grarco/tx-batch
grarco May 10, 2024
97a2d8d
Restores `batch_size` arg for `fetch`
grarco May 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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))
2 changes: 2 additions & 0 deletions Cargo.lock

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

84 changes: 57 additions & 27 deletions crates/apps/src/lib/bench_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,12 @@ use namada::ledger::queries::{
};
use namada::state::StorageRead;
use namada::tx::data::pos::Bond;
use namada::tx::data::{Fee, TxResult, VpsResult};
use namada::tx::{Authorization, Code, Data, Section, Tx};
use namada::tx::data::{
BatchResults, BatchedTxResult, Fee, TxResult, VpsResult,
};
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 @@ -237,7 +241,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 @@ -262,7 +266,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 @@ -288,7 +292,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 @@ -324,10 +328,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 @@ -340,10 +349,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 @@ -387,14 +397,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 @@ -601,7 +615,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 @@ -620,7 +634,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 @@ -882,27 +897,41 @@ impl Client for BenchShell {
self.last_block_masp_txs
.iter()
.enumerate()
.map(|(idx, (_tx, changed_keys))| {
let tx_result = TxResult {
.map(|(idx, (tx, changed_keys))| {
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![],
ibc_events: BTreeSet::default(),
eth_bridge_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![],
ibc_events: BTreeSet::default(),
eth_bridge_events: BTreeSet::default(),
}),
)]
.into_iter()
.collect(),
),
};
namada::tendermint::abci::Event {
kind: "applied".to_string(),
// Mock the masp and tx attributes
attributes: vec![
namada::tendermint::abci::EventAttribute {
key: "is_valid_masp_tx".to_string(),
key: format!(
"cmt/{}/is_valid_masp_tx",
tx.first_commitments()
.unwrap()
.get_hash()
),
value: format!("{}", idx),
index: true,
},
namada::tendermint::abci::EventAttribute {
key: "inner_tx".to_string(),
key: "batch".to_string(),
value: tx_result.to_string(),
index: true,
},
Expand Down Expand Up @@ -1015,7 +1044,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 All @@ -1027,7 +1056,6 @@ impl BenchShieldedCtx {
self.shielded,
&self.shell,
&StdIo,
1,
None,
None,
&[spending_key.into()],
Expand Down Expand Up @@ -1112,7 +1140,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 @@ -1152,8 +1180,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 @@ -1166,7 +1196,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
1 change: 0 additions & 1 deletion crates/apps/src/lib/cli/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,6 @@ impl CliApi {
chain_ctx.shielded,
&client,
&io,
args.batch_size,
args.start_query_height,
args.last_query_height,
&sks,
Expand Down
2 changes: 0 additions & 2 deletions crates/apps/src/lib/client/masp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ pub async fn syncing<
mut shielded: ShieldedContext<U>,
client: &C,
io: &IO,
batch_size: u64,
start_query_height: Option<BlockHeight>,
last_query_height: Option<BlockHeight>,
sks: &[ExtendedSpendingKey],
Expand All @@ -44,7 +43,6 @@ pub async fn syncing<
&logger,
start_query_height,
last_query_height,
batch_size,
sks,
fvks,
)
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 @@ -48,7 +48,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, prompt, Namada};
use tokio::time::Instant;
Expand Down Expand Up @@ -2591,7 +2591,7 @@ pub async fn query_result(context: &impl Namada, args: args::QueryResult) {
.await;
match inner_resp {
Ok(resp) => {
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 @@ -756,6 +759,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 @@ -764,7 +768,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 @@ -1063,9 +1067,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
Loading