From 5025390a1062b2af8e5dd24e7a39eb9e5f57b1f3 Mon Sep 17 00:00:00 2001 From: Simon Kamp Date: Tue, 21 Sep 2021 14:03:43 +0200 Subject: [PATCH 1/6] Trace account tool supports all tx types (with cost/rewards), does not fail when outcome is reject --- mobile_wallet/Cargo.lock | 82 +---- rust-bins/src/bin/trace_account.rs | 477 +++++++++++++++++++---------- 2 files changed, 314 insertions(+), 245 deletions(-) diff --git a/mobile_wallet/Cargo.lock b/mobile_wallet/Cargo.lock index 02703355f..1aabb36ec 100644 --- a/mobile_wallet/Cargo.lock +++ b/mobile_wallet/Cargo.lock @@ -114,12 +114,6 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" -[[package]] -name = "bytes" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" - [[package]] name = "cc" version = "1.0.67" @@ -279,13 +273,10 @@ version = "0.1.0" dependencies = [ "anyhow", "byteorder", - "bytes", "crypto_common", "crypto_common_derive", "ff", - "ffi_helpers", "group", - "libc", "pairing", "rand", "serde", @@ -328,7 +319,6 @@ dependencies = [ name = "dodis_yampolskiy_prf" version = "0.1.0" dependencies = [ - "clear_on_drop", "crypto_common", "crypto_common_derive", "curve_arithmetic", @@ -393,7 +383,6 @@ name = "elgamal" version = "0.1.0" dependencies = [ "anyhow", - "clear_on_drop", "crypto_common", "crypto_common_derive", "curve_arithmetic", @@ -415,7 +404,6 @@ dependencies = [ "crypto_common", "crypto_common_derive", "curve_arithmetic", - "eddsa_ed25519", "elgamal", "ff", "ffi_helpers", @@ -427,8 +415,6 @@ dependencies = [ "rand", "random_oracle", "serde", - "sha2 0.9.3", - "sha3", "wasm-bindgen", ] @@ -464,7 +450,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5796e7d62ca01a00ed3a649b0da1ffa1ac8f06bcad40339df09dbdd69a05ba9" dependencies = [ - "num-bigint 0.2.6", + "num-bigint", "num-integer", "num-traits", "proc-macro2", @@ -546,7 +532,6 @@ dependencies = [ "bulletproofs", "byteorder", "chrono", - "clear_on_drop", "crypto_common", "crypto_common_derive", "curve_arithmetic", @@ -561,18 +546,15 @@ dependencies = [ "hex", "itertools", "libc", - "num", "pairing", "pedersen_scheme", "ps_sig", "rand", "rand_core", "random_oracle", - "rayon", "serde", "serde_json", "sha2 0.9.3", - "sha3", "thiserror", "wasm-bindgen", ] @@ -665,7 +647,7 @@ dependencies = [ [[package]] name = "mobile_wallet" -version = "0.8.0" +version = "0.9.0" dependencies = [ "anyhow", "byteorder", @@ -693,20 +675,6 @@ dependencies = [ "sha2 0.9.3", ] -[[package]] -name = "num" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f" -dependencies = [ - "num-bigint 0.3.2", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.2.6" @@ -718,26 +686,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-bigint" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d0a3d5e207573f948a9e5376662aa743a2ea13f7c50a554d7af443a73fbfeba" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5" -dependencies = [ - "num-traits", -] - [[package]] name = "num-integer" version = "0.1.44" @@ -748,29 +696,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-iter" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" -dependencies = [ - "autocfg", - "num-bigint 0.3.2", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.14" @@ -819,7 +744,6 @@ name = "pedersen_scheme" version = "0.1.0" dependencies = [ "byteorder", - "clear_on_drop", "crypto_common", "crypto_common_derive", "curve_arithmetic", @@ -942,9 +866,7 @@ dependencies = [ "crypto_common", "crypto_common_derive", "curve_arithmetic", - "itertools", "rand", - "rand_core", "sha3", ] diff --git a/rust-bins/src/bin/trace_account.rs b/rust-bins/src/bin/trace_account.rs index efd256e9d..3a2b70ebe 100644 --- a/rust-bins/src/bin/trace_account.rs +++ b/rust-bins/src/bin/trace_account.rs @@ -104,7 +104,7 @@ struct Origin { } /// Interesting parts of the response for a single transaction. -#[derive(SerdeDeserialize)] +#[derive(SerdeDeserialize, Debug)] #[serde(rename_all = "camelCase")] struct TransactionResponse { id: u64, @@ -114,7 +114,8 @@ struct TransactionResponse { transaction_hash: Option, details: Details, subtotal: Option, - total: Option, + total: Option, /* todo according to https://github.com/Concordium/concordium-wallet-proxy#total-required total is required */ + cost: Option, } /// Outcome of a transaction. #[derive(SerdeDeserialize, Eq, PartialEq, Debug)] @@ -127,9 +128,9 @@ enum Outcome { /// Details of a particular transaction. The actual details are transaction /// specific, and are thus handled by the enumeration `AdditionalDetails`. -#[derive(SerdeDeserialize)] +#[derive(SerdeDeserialize, Debug)] struct Details { - outcome: Option, + outcome: Option, /* todo according to https://github.com/Concordium/concordium-wallet-proxy#details-required outcome is required */ #[serde(flatten)] additional_details: AdditionalDetails, } @@ -144,15 +145,18 @@ enum AdditionalDetails { InitContract, #[serde(rename = "update")] Update, - #[serde(rename = "transfer")] + #[serde(rename = "transfer", alias = "transferWithMemo")] SimpleTransfer(SimpleTransfer), - #[serde(rename = "encryptedAmountTransfer")] + #[serde( + rename = "encryptedAmountTransfer", + alias = "encryptedAmountTransferWithMemo" + )] EncryptedAmountTransfer(EncryptedTransfer), #[serde(rename = "transferToEncrypted")] TransferToEncrypted(TransferToEncrypted), #[serde(rename = "transferToPublic")] TransferToPublic(TransferToPublic), - #[serde(rename = "transferWithSchedule")] + #[serde(rename = "transferWithSchedule", alias = "transferWithScheduleAndMemo")] TransferWithSchedule(TransferWithSchedule), #[serde(rename = "blockReward")] BlockReward, @@ -162,50 +166,90 @@ enum AdditionalDetails { BakingReward, #[serde(rename = "platformDevelopmentCharge")] Mint, + #[serde(rename = "deployModule")] + DeployModule, + #[serde(rename = "addBaker")] + AddBaker, + #[serde(rename = "removeBaker")] + RemoveBaker, + #[serde(rename = "updateBakerStake")] + UpdateBakerStake, + #[serde(rename = "updateBakerKeys")] + UpdateBakerKeys, + #[serde(rename = "updateBakerRestakeEarnings")] + UpdateBakerRestakeEarnings, + #[serde(rename = "registerData")] + RegisterData, + #[serde(rename = "deployCredential")] + DeployCredential, + #[serde(rename = "updateCredentials")] + UpdateCredentials, + #[serde(rename = "updateAccountKeys")] + UpdateAccountKeys, #[serde(other)] Uninteresting, } #[derive(SerdeDeserialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct SimpleTransfer { - transfer_source: AccountAddress, - transfer_destination: AccountAddress, - transfer_amount: Amount, +#[serde(untagged)] +pub enum SimpleTransfer { + #[serde(rename_all = "camelCase")] + Success { + transfer_source: AccountAddress, + transfer_destination: AccountAddress, + transfer_amount: Amount, + }, + Reject {}, } #[derive(SerdeDeserialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct EncryptedTransfer { - transfer_source: AccountAddress, - transfer_destination: AccountAddress, - encrypted_amount: EncryptedAmount, - input_encrypted_amount: EncryptedAmount, - new_self_encrypted_amount: EncryptedAmount, +#[serde(untagged)] +pub enum EncryptedTransfer { + #[serde(rename_all = "camelCase")] + Success { + transfer_source: AccountAddress, + transfer_destination: AccountAddress, + encrypted_amount: EncryptedAmount, + input_encrypted_amount: EncryptedAmount, + new_self_encrypted_amount: EncryptedAmount, + }, + Reject {}, } #[derive(SerdeDeserialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct TransferWithSchedule { - transfer_destination: AccountAddress, - transfer_amount: Amount, +#[serde(untagged)] +pub enum TransferWithSchedule { + #[serde(rename_all = "camelCase")] + Success { + transfer_destination: AccountAddress, + transfer_amount: Amount, + }, + Reject {}, } #[derive(SerdeDeserialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct TransferToEncrypted { - transfer_source: AccountAddress, - amount_subtracted: Amount, - new_self_encrypted_amount: EncryptedAmount, +#[serde(untagged)] +pub enum TransferToEncrypted { + #[serde(rename_all = "camelCase")] + Success { + transfer_source: AccountAddress, + amount_subtracted: Amount, + new_self_encrypted_amount: EncryptedAmount, + }, + Reject {}, } #[derive(SerdeDeserialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct TransferToPublic { - transfer_source: AccountAddress, - amount_added: Amount, - input_encrypted_amount: EncryptedAmount, - new_self_encrypted_amount: EncryptedAmount, +#[serde(untagged)] +pub enum TransferToPublic { + #[serde(rename_all = "camelCase")] + Success { + transfer_source: AccountAddress, + amount_added: Amount, + input_encrypted_amount: EncryptedAmount, + new_self_encrypted_amount: EncryptedAmount, + }, + Reject {}, } /// A success response from accBalance endpoint @@ -256,7 +300,7 @@ struct Trace { #[structopt( long = "source", help = "URL to the wallet-proxy instance.", - default_value = "https://wallet-proxy.eu.staging.concordium.com" + default_value = "https://wallet-proxy.stagenet.concordium.com" )] source: url::Url, #[structopt(subcommand)] @@ -449,60 +493,22 @@ fn trace_single_account( .expect("Could not write."); } AdditionalDetails::SimpleTransfer(st) => { - if tx.origin.origin_type == OriginType::Own { - writeln!( - writer, - "[{}] {}: Outgoing transfer of {} GTU to account {}.\n \ - Block hash: {}\n Transaction hash: {}", - pretty_time(tx.block_time), - i, - st.transfer_amount, - st.transfer_destination, - tx.block_hash, - tx.transaction_hash.as_ref().unwrap(), - ) - .expect("Could not write."); - } else { - writeln!( - writer, - "[{}] {}: Incoming transfer of {} GTU from account {}.\n \ - Block hash: {}\n Transaction hash: {}", - pretty_time(tx.block_time), - i, - st.transfer_amount, - st.transfer_source, - tx.block_hash, - tx.transaction_hash.as_ref().unwrap(), - ) - .expect("Could not write."); - } - } - - AdditionalDetails::EncryptedAmountTransfer(et) => { - if tx.origin.origin_type == OriginType::Own { - if let Some(sk) = &sk { - let before = encrypted_transfers::decrypt_amount( - &table, - &sk, - &et.input_encrypted_amount, - ); - let after = encrypted_transfers::decrypt_amount( - &table, - &sk, - &et.new_self_encrypted_amount, - ); - assert!(before >= after); - let amount = Amount { - microgtu: before.microgtu - after.microgtu, - }; + if let SimpleTransfer::Success { + transfer_source, + transfer_destination, + transfer_amount, + } = st + { + if tx.origin.origin_type == OriginType::Own { writeln!( writer, - "[{}] {}: outgoing encrypted transfer of {} GTU to \ - account {}.\n Block hash: {}\n Transaction hash: {}", + "[{}] {}: Outgoing transfer of {} GTU + to account {}.\n Block hash: {}\n Transaction hash: + {}", pretty_time(tx.block_time), i, - amount, - et.transfer_destination, + transfer_amount, + transfer_destination, tx.block_hash, tx.transaction_hash.as_ref().unwrap(), ) @@ -510,113 +516,211 @@ fn trace_single_account( } else { writeln!( writer, - "[{}] {}: outgoing encrypted transfer to account {}.\n \ - Block hash: {}\n Transaction hash: {}", + "[{}] {}: Incoming transfer of {} GTU + from account {}.\n Block hash: {}\n Transaction + hash: {}", pretty_time(tx.block_time), i, - et.transfer_destination, + transfer_amount, + transfer_source, tx.block_hash, tx.transaction_hash.as_ref().unwrap(), ) .expect("Could not write."); } - } else if tx.origin.origin_type == OriginType::Account { - if let Some(sk) = &sk { - let amount = encrypted_transfers::decrypt_amount( - &table, - &sk, - &et.encrypted_amount, - ); - writeln!( - writer, - "[{}] {}: incoming encrypted transfer of {} GTU from \ - account {}\n Block hash: {}\n Transaction hash: {}", - pretty_time(tx.block_time), - i, - amount, - et.transfer_source, - tx.block_hash, - tx.transaction_hash.as_ref().unwrap(), - ) - .expect("Could not write.") - } else { - writeln!( - writer, - "[{}] {}: incoming encrypted transfer from \ - account {}\n Block hash: {}\n Transaction \ - hash: {}", - pretty_time(tx.block_time), - i, - et.transfer_source, - tx.block_hash, - tx.transaction_hash.as_ref().unwrap() - ) - .expect("Could not write.") + } else { + eprintln!("Missing fields in successful Transfer"); + break; // or panic? todo the same for all + // instances + } + } + + AdditionalDetails::EncryptedAmountTransfer(et) => { + if let EncryptedTransfer::Success { + transfer_source, + transfer_destination, + encrypted_amount, + input_encrypted_amount, + new_self_encrypted_amount, + } = et + { + if tx.origin.origin_type == OriginType::Own { + if let Some(sk) = &sk { + let before = encrypted_transfers::decrypt_amount( + &table, + &sk, + &input_encrypted_amount, + ); + let after = encrypted_transfers::decrypt_amount( + &table, + &sk, + &new_self_encrypted_amount, + ); + assert!(before >= after); + let amount = Amount { + microgtu: before.microgtu - after.microgtu, + }; + writeln!( + writer, + "[{}] {}: outgoing encrypted + transfer of {} GTU to account {}.\n Block hash: + {}\n Transaction hash: {}", + pretty_time(tx.block_time), + i, + amount, + transfer_destination, + tx.block_hash, + tx.transaction_hash.as_ref().unwrap(), + ) + .expect("Could not write."); + } else { + writeln!( + writer, + "[{}] {}: outgoing encrypted + transfer to account {}.\n Block hash: {}\n + Transaction hash: {}", + pretty_time(tx.block_time), + i, + transfer_destination, + tx.block_hash, + tx.transaction_hash.as_ref().unwrap(), + ) + .expect("Could not write."); + } + } else if tx.origin.origin_type == OriginType::Account { + if let Some(sk) = &sk { + let amount = encrypted_transfers::decrypt_amount( + &table, + &sk, + &encrypted_amount, + ); + writeln!( + writer, + "[{}] {}: incoming encrypted + transfer of {} GTU from account {}\n Block hash: {}\n + Transaction hash: {}", + pretty_time(tx.block_time), + i, + amount, + transfer_source, + tx.block_hash, + tx.transaction_hash.as_ref().unwrap(), + ) + .expect("Could not write.") + } else { + writeln!( + writer, + "[{}] {}: incoming encrypted + transfer from account {}\n Block hash: {}\n + Transaction hash: {}", + pretty_time(tx.block_time), + i, + transfer_source, + tx.block_hash, + tx.transaction_hash.as_ref().unwrap() + ) + .expect("Could not write.") + } } + } else { + eprintln!("Missing fields in successful Encrypted transfer"); + break; } } AdditionalDetails::TransferToEncrypted(tte) => { - writeln!( - writer, - "[{}] {}: account {} shielded {} GTU\n Block hash: {}\n \ - Transaction hash: {}", - pretty_time(tx.block_time), - i, - tte.transfer_source, - tte.amount_subtracted, - tx.block_hash, - tx.transaction_hash.as_ref().unwrap() - ) - .expect("Could not write."); - } - AdditionalDetails::TransferToPublic(ttp) => { - writeln!( - writer, - "[{}] {}: account {} unshielded {} GTU\n Block hash: {}\n \ - Transaction hash: {}", - pretty_time(tx.block_time), - i, - ttp.transfer_source, - ttp.amount_added, - tx.block_hash, - tx.transaction_hash.as_ref().unwrap() - ) - .expect("Could not write."); - } - AdditionalDetails::TransferWithSchedule(tws) => { - if tx.origin.origin_type == OriginType::Own { + if let TransferToEncrypted::Success { + transfer_source, + amount_subtracted, + new_self_encrypted_amount: _, + } = tte + { writeln!( writer, - "[{}] {}: Outgoing scheduled transfer of {} GTU to account \ - {}\n Block hash: {}\n Transaction hash: {}", + "[{}] {}: account {} shielded {} GTU\n + Block hash: {}\n Transaction hash: {}", pretty_time(tx.block_time), i, - tws.transfer_amount, - tws.transfer_destination, + transfer_source, + amount_subtracted, tx.block_hash, tx.transaction_hash.as_ref().unwrap() ) .expect("Could not write."); - } else if let AmountDelta::PositiveAmount(am) = - tx.total.as_ref().unwrap() + } else { + eprintln!("Missing fields in successful Transfer to encrypted"); + break; + } + } + AdditionalDetails::TransferToPublic(ttp) => { + if let TransferToPublic::Success { + transfer_source, + amount_added, + input_encrypted_amount: _, + new_self_encrypted_amount: _, + } = ttp { writeln!( writer, - "[{}] {}: Incoming scheduled transfer of {} GTU from account \ - {}\n Block hash: {}\n Transaction hash: {}", + "[{}] {}: account {} unshielded {} GTU\n + Block hash: {}\n Transaction hash: {}", pretty_time(tx.block_time), i, - am, - tx.origin.address.as_ref().unwrap(), + transfer_source, + amount_added, tx.block_hash, tx.transaction_hash.as_ref().unwrap() ) .expect("Could not write."); } else { - panic!( - "Malformed transaction details. Incoming scheduled transfer \ - with negative balance" - ); + eprintln!("Missing fields in successful Transfer to public"); + break; + } + } + AdditionalDetails::TransferWithSchedule(tws) => { + if let TransferWithSchedule::Success { + transfer_destination, + transfer_amount, + } = tws + { + if tx.origin.origin_type == OriginType::Own { + writeln!( + writer, + "[{}] {}: Outgoing scheduled transfer + of {} GTU to account {}\n Block hash: {}\n + Transaction hash: {}", + pretty_time(tx.block_time), + i, + transfer_amount, + transfer_destination, + tx.block_hash, + tx.transaction_hash.as_ref().unwrap() + ) + .expect("Could not write."); + } else if let AmountDelta::PositiveAmount(am) = + tx.total.as_ref().unwrap() + { + writeln!( + writer, + "[{}] {}: Incoming scheduled transfer + of {} GTU from account {}\n Block hash: {}\n + Transaction hash: {}", + pretty_time(tx.block_time), + i, + am, + tx.origin.address.as_ref().unwrap(), + tx.block_hash, + tx.transaction_hash.as_ref().unwrap() + ) + .expect("Could not write."); + } else { + panic!( + "Malformed transaction details. + Incoming scheduled transfer with negative balance" + ); + } + } else { + eprintln!("Missing fields in successful Transfer with schedule"); + break; } } AdditionalDetails::BlockReward @@ -626,7 +730,8 @@ fn trace_single_account( if let AmountDelta::PositiveAmount(am) = tx.total.as_ref().unwrap() { writeln!( writer, - "[{}] {}: Received a {} reward of {} GTU\n Block hash: {}", + "[{}] {}: Received a {} reward of {} + GTU\n Block hash: {}", pretty_time(tx.block_time), i, match &tx.details.additional_details { @@ -641,7 +746,49 @@ fn trace_single_account( ) .expect("Could not write."); } else { - panic!("Malformed transaction details. Negative reward"); + panic!( + "Malformed transaction details. + Negative reward" + ); + } + } + AdditionalDetails::AddBaker + | AdditionalDetails::DeployModule + | AdditionalDetails::RemoveBaker + | AdditionalDetails::UpdateBakerStake + | AdditionalDetails::UpdateBakerKeys + | AdditionalDetails::UpdateBakerRestakeEarnings + | AdditionalDetails::RegisterData + | AdditionalDetails::DeployCredential + | AdditionalDetails::UpdateCredentials + | AdditionalDetails::UpdateAccountKeys => { + if let Some(am) = tx.cost { + writeln!( + writer, + "[{}] {}: {} resulting in a change of balance \ + of {} GTUs\n Block hash: {}\n Transaction hash: {}", + pretty_time(tx.block_time), + i, + match tx.details.additional_details {// todo can any of the transactions below affect other accounts? + AdditionalDetails::AddBaker => "added as baker account", //todo check wording + AdditionalDetails::DeployModule => "deployed a module", + AdditionalDetails::RemoveBaker => "removed as baker account", // todo check wording + AdditionalDetails::UpdateBakerStake => "updated its baker stake", // todo check wording + AdditionalDetails::UpdateBakerKeys => "updated its baker keys",// todo check wording + AdditionalDetails::UpdateBakerRestakeEarnings => "updated its baker restake earnings", // todo check wording + AdditionalDetails::RegisterData => "registered data", + AdditionalDetails::DeployCredential => "deployed a credential", + AdditionalDetails::UpdateCredentials => "updated its credentials",// todo check wording + AdditionalDetails::UpdateAccountKeys => "updated its account keys",// todo check wording + _ => unreachable!(), + + }, + am, + tx.block_hash, + tx.transaction_hash.as_ref().unwrap() + ).expect("Could not write."); + } else { + panic!("Missing cost field of outgoing transaction: {:?}", tx); } } AdditionalDetails::Uninteresting => { From 4c82ae2a59c1de23e931d4700cb71c5d8ccdcda8 Mon Sep 17 00:00:00 2001 From: Simon Kamp Date: Tue, 21 Sep 2021 14:28:01 +0200 Subject: [PATCH 2/6] Remove option from required fields `total` and `outcome` --- rust-bins/src/bin/trace_account.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/rust-bins/src/bin/trace_account.rs b/rust-bins/src/bin/trace_account.rs index 3a2b70ebe..479aed1b7 100644 --- a/rust-bins/src/bin/trace_account.rs +++ b/rust-bins/src/bin/trace_account.rs @@ -114,7 +114,7 @@ struct TransactionResponse { transaction_hash: Option, details: Details, subtotal: Option, - total: Option, /* todo according to https://github.com/Concordium/concordium-wallet-proxy#total-required total is required */ + total: AmountDelta, cost: Option, } /// Outcome of a transaction. @@ -130,7 +130,7 @@ enum Outcome { /// specific, and are thus handled by the enumeration `AdditionalDetails`. #[derive(SerdeDeserialize, Debug)] struct Details { - outcome: Option, /* todo according to https://github.com/Concordium/concordium-wallet-proxy#details-required outcome is required */ + outcome: Outcome, #[serde(flatten)] additional_details: AdditionalDetails, } @@ -457,12 +457,7 @@ fn trace_single_account( match rq { Ok(response) => { for tx in response.transactions.iter() { - if tx - .details - .outcome - .as_ref() - .map_or(false, |x| x == &Outcome::Reject) - { + if tx.details.outcome == Outcome::Reject { continue; } match &tx.details.additional_details { @@ -696,9 +691,7 @@ fn trace_single_account( tx.transaction_hash.as_ref().unwrap() ) .expect("Could not write."); - } else if let AmountDelta::PositiveAmount(am) = - tx.total.as_ref().unwrap() - { + } else if let AmountDelta::PositiveAmount(am) = tx.total { writeln!( writer, "[{}] {}: Incoming scheduled transfer @@ -727,7 +720,7 @@ fn trace_single_account( | AdditionalDetails::FinalizationReward | AdditionalDetails::BakingReward | AdditionalDetails::Mint => { - if let AmountDelta::PositiveAmount(am) = tx.total.as_ref().unwrap() { + if let AmountDelta::PositiveAmount(am) = tx.total { writeln!( writer, "[{}] {}: Received a {} reward of {} From 2860772116e869ca71797ea57049004a997e562d Mon Sep 17 00:00:00 2001 From: Simon Kamp Date: Tue, 21 Sep 2021 16:13:45 +0200 Subject: [PATCH 3/6] Add output for most cases of outcome=reject --- rust-bins/src/bin/trace_account.rs | 47 ++++++++++++++++++------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/rust-bins/src/bin/trace_account.rs b/rust-bins/src/bin/trace_account.rs index 479aed1b7..c4bd92468 100644 --- a/rust-bins/src/bin/trace_account.rs +++ b/rust-bins/src/bin/trace_account.rs @@ -448,6 +448,27 @@ fn trace_single_account( Err(e) => Err(format!("Request cannot be made {}", e)), } }; + + fn rejected_tx_with_cost(writer: &mut impl std::io::Write, i: u64, tx: &TransactionResponse, event: &str) { + if let Some(am) = tx.cost { + writeln!( + writer, + "[{}] {}: Rejected {} resulting in a cost of {} GTU + .\n Block hash: {}\n Transaction hash: + {}", + pretty_time(tx.block_time), + i, + event, + am, + tx.block_hash, + tx.transaction_hash.as_ref().unwrap(), + ) + .expect("Could not write."); + } else { + panic!("Cost field missing for rejected {}: {:?}", event, tx); + } + } + let mut init = None; let mut i = 0u64; let sk = &input.encryption_secret_key; @@ -457,9 +478,6 @@ fn trace_single_account( match rq { Ok(response) => { for tx in response.transactions.iter() { - if tx.details.outcome == Outcome::Reject { - continue; - } match &tx.details.additional_details { AdditionalDetails::InitContract => { writeln!( @@ -473,7 +491,7 @@ fn trace_single_account( tx.transaction_hash.as_ref().unwrap() ) .expect("Could not write."); - } + } // todo what if this tx fails? Is the cost different? If not should the output change? AdditionalDetails::Update => { writeln!( writer, @@ -486,7 +504,7 @@ fn trace_single_account( tx.transaction_hash.as_ref().unwrap() ) .expect("Could not write."); - } + } // todo what if this tx fails? Is the cost different? If not should the output change? AdditionalDetails::SimpleTransfer(st) => { if let SimpleTransfer::Success { transfer_source, @@ -524,12 +542,9 @@ fn trace_single_account( .expect("Could not write."); } } else { - eprintln!("Missing fields in successful Transfer"); - break; // or panic? todo the same for all - // instances + rejected_tx_with_cost(writer, i, tx, "transfer"); } } - AdditionalDetails::EncryptedAmountTransfer(et) => { if let EncryptedTransfer::Success { transfer_source, @@ -618,8 +633,7 @@ fn trace_single_account( } } } else { - eprintln!("Missing fields in successful Encrypted transfer"); - break; + rejected_tx_with_cost(writer, i, tx, "encrypted transfer"); } } AdditionalDetails::TransferToEncrypted(tte) => { @@ -642,8 +656,7 @@ fn trace_single_account( ) .expect("Could not write."); } else { - eprintln!("Missing fields in successful Transfer to encrypted"); - break; + rejected_tx_with_cost(writer, i, tx, "shielding"); } } AdditionalDetails::TransferToPublic(ttp) => { @@ -667,8 +680,7 @@ fn trace_single_account( ) .expect("Could not write."); } else { - eprintln!("Missing fields in successful Transfer to public"); - break; + rejected_tx_with_cost(writer, i, tx, "unshielding"); } } AdditionalDetails::TransferWithSchedule(tws) => { @@ -712,8 +724,7 @@ fn trace_single_account( ); } } else { - eprintln!("Missing fields in successful Transfer with schedule"); - break; + rejected_tx_with_cost(writer, i, tx, "transfer with schedule"); } } AdditionalDetails::BlockReward @@ -782,7 +793,7 @@ fn trace_single_account( ).expect("Could not write."); } else { panic!("Missing cost field of outgoing transaction: {:?}", tx); - } + } // todo what if this tx fails? Is the cost different? If not should the output change? } AdditionalDetails::Uninteresting => { // do nothing for other transaction types. From 71f9abcf4b1b2bde34c7d403883929c25932e841 Mon Sep 17 00:00:00 2001 From: Simon Kamp Date: Tue, 21 Sep 2021 16:15:46 +0200 Subject: [PATCH 4/6] fmt --- rust-bins/src/bin/trace_account.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/rust-bins/src/bin/trace_account.rs b/rust-bins/src/bin/trace_account.rs index c4bd92468..624a58e5c 100644 --- a/rust-bins/src/bin/trace_account.rs +++ b/rust-bins/src/bin/trace_account.rs @@ -449,7 +449,12 @@ fn trace_single_account( } }; - fn rejected_tx_with_cost(writer: &mut impl std::io::Write, i: u64, tx: &TransactionResponse, event: &str) { + fn rejected_tx_with_cost( + writer: &mut impl std::io::Write, + i: u64, + tx: &TransactionResponse, + event: &str, + ) { if let Some(am) = tx.cost { writeln!( writer, @@ -491,7 +496,8 @@ fn trace_single_account( tx.transaction_hash.as_ref().unwrap() ) .expect("Could not write."); - } // todo what if this tx fails? Is the cost different? If not should the output change? + } /* todo what if this tx fails? Is the cost different? If not should the + * output change? */ AdditionalDetails::Update => { writeln!( writer, @@ -504,7 +510,8 @@ fn trace_single_account( tx.transaction_hash.as_ref().unwrap() ) .expect("Could not write."); - } // todo what if this tx fails? Is the cost different? If not should the output change? + } /* todo what if this tx fails? Is the cost different? If not should the + * output change? */ AdditionalDetails::SimpleTransfer(st) => { if let SimpleTransfer::Success { transfer_source, @@ -793,7 +800,8 @@ fn trace_single_account( ).expect("Could not write."); } else { panic!("Missing cost field of outgoing transaction: {:?}", tx); - } // todo what if this tx fails? Is the cost different? If not should the output change? + } // todo what if this tx fails? Is the cost + // different? If not should the output change? } AdditionalDetails::Uninteresting => { // do nothing for other transaction types. From bd3a381ba3f2b0199f4251fc8b38c09f8d336042 Mon Sep 17 00:00:00 2001 From: Simon Kamp Date: Tue, 21 Sep 2021 16:20:58 +0200 Subject: [PATCH 5/6] fmt --- rust-bins/src/bin/trace_account.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust-bins/src/bin/trace_account.rs b/rust-bins/src/bin/trace_account.rs index 624a58e5c..00380c825 100644 --- a/rust-bins/src/bin/trace_account.rs +++ b/rust-bins/src/bin/trace_account.rs @@ -496,8 +496,8 @@ fn trace_single_account( tx.transaction_hash.as_ref().unwrap() ) .expect("Could not write."); - } /* todo what if this tx fails? Is the cost different? If not should the - * output change? */ + } // todo what if this tx fails? Is the cost different? If not should the + // output change? AdditionalDetails::Update => { writeln!( writer, @@ -510,8 +510,8 @@ fn trace_single_account( tx.transaction_hash.as_ref().unwrap() ) .expect("Could not write."); - } /* todo what if this tx fails? Is the cost different? If not should the - * output change? */ + } // todo what if this tx fails? Is the cost different? If not should the + // output change? AdditionalDetails::SimpleTransfer(st) => { if let SimpleTransfer::Success { transfer_source, From 11d1a7fee00a74f1e0b1c1fad6533296fe39f1ac Mon Sep 17 00:00:00 2001 From: Simon Kamp Date: Tue, 21 Sep 2021 16:56:23 +0200 Subject: [PATCH 6/6] Added case for missing subtotal for init contract --- rust-bins/src/bin/trace_account.rs | 34 +++++++++++++++++++----------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/rust-bins/src/bin/trace_account.rs b/rust-bins/src/bin/trace_account.rs index 00380c825..72499e982 100644 --- a/rust-bins/src/bin/trace_account.rs +++ b/rust-bins/src/bin/trace_account.rs @@ -485,18 +485,27 @@ fn trace_single_account( for tx in response.transactions.iter() { match &tx.details.additional_details { AdditionalDetails::InitContract => { - writeln!( - writer, - "[{}] {}: initialized a contract resulting in a change of balance \ - of {} GTUs\n Block hash: {}\n Transaction hash: {}", - pretty_time(tx.block_time), - i, - tx.subtotal.as_ref().unwrap(), - tx.block_hash, - tx.transaction_hash.as_ref().unwrap() - ) - .expect("Could not write."); - } // todo what if this tx fails? Is the cost different? If not should the + if let Some(subtotal) = &tx.subtotal { + writeln!( + writer, + "[{}] {}: initialized a contract resulting in a change of \ + balance of {} GTUs\n Block hash: {}\n Transaction \ + hash: {}", + pretty_time(tx.block_time), + i, + subtotal, + tx.block_hash, + tx.transaction_hash.as_ref().unwrap() + ) + .expect("Could not write."); + // todo according to https://github.com/Concordium/concordium-wallet-proxy#subtotal-optional + // subtotal does not include transaction fees. I think we should be using total, or maybe report both? + } else { + panic!("No subtotal: {:?}", tx); + // todo this seems to only happen when outcome=reject + } + } /* todo what if this tx fails? Is it equivalent to checking missing + * subtotal? Is the cost different? If not should the */ // output change? AdditionalDetails::Update => { writeln!( @@ -510,6 +519,7 @@ fn trace_single_account( tx.transaction_hash.as_ref().unwrap() ) .expect("Could not write."); + // todo in this case we probably also want total rather than subtotal? } // todo what if this tx fails? Is the cost different? If not should the // output change? AdditionalDetails::SimpleTransfer(st) => {