diff --git a/Cargo.lock b/Cargo.lock index 6280fc717c..2ff91f7dd2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -680,30 +680,38 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.11" +version = "4.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42dfd32784433290c51d92c438bb72ea5063797fc3cc9a21a8c4346bebbb2098" +checksum = "906f7fe1da4185b7a282b2bc90172a496f9def1aca4545fe7526810741591e14" dependencies = [ - "bitflags 2.0.2", + "clap_builder", "clap_derive", - "clap_lex 0.3.0", - "is-terminal", "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351f9ad9688141ed83dfd8f5fb998a06225ef444b48ff4dc43de6d409b7fd10b" +dependencies = [ + "bitflags 1.3.2", + "clap_lex 0.4.1", + "is-terminal", "strsim 0.10.0", "termcolor", ] [[package]] name = "clap_derive" -version = "4.1.9" +version = "4.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fddf67631444a3a3e3e5ac51c36a5e01335302de677bd78759eaa90ab1f46644" +checksum = "81d7dc0031c3a59a04fc2ba395c8e2dd463cba1859275f065d225f6122221b45" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.12", ] [[package]] @@ -717,12 +725,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" -dependencies = [ - "os_str_bytes", -] +checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" [[package]] name = "clear_on_drop" @@ -1160,9 +1165,9 @@ dependencies = [ [[package]] name = "dirs" -version = "4.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ "dirs-sys", ] @@ -1179,13 +1184,14 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.3.6" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", + "option-ext", "redox_users", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -1589,7 +1595,7 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" name = "go-grpc-gateway-testing" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "displaydoc", "futures", "grpcio", @@ -2296,7 +2302,7 @@ dependencies = [ name = "mc-admin-http-gateway" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "grpcio", "mc-common", "mc-util-grpc", @@ -2843,7 +2849,7 @@ dependencies = [ name = "mc-consensus-mint-client" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "displaydoc", "grpcio", "hex", @@ -2915,7 +2921,7 @@ dependencies = [ name = "mc-consensus-scp-play" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "mc-common", "mc-consensus-scp", "mc-transaction-core", @@ -2945,7 +2951,7 @@ version = "5.0.5" dependencies = [ "base64 0.21.0", "chrono", - "clap 4.1.11", + "clap 4.1.14", "curve25519-dalek", "displaydoc", "fs_extra", @@ -3009,7 +3015,7 @@ name = "mc-consensus-service-config" version = "5.0.5" dependencies = [ "base64 0.21.0", - "clap 4.1.11", + "clap 4.1.14", "displaydoc", "hex", "mc-attest-core", @@ -3035,7 +3041,7 @@ dependencies = [ name = "mc-consensus-tool" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "grpcio", "mc-common", "mc-connection", @@ -3050,7 +3056,7 @@ name = "mc-core" version = "5.0.5" dependencies = [ "anyhow", - "clap 4.1.11", + "clap 4.1.14", "curve25519-dalek", "ed25519-dalek", "generic-array", @@ -3341,7 +3347,7 @@ name = "mc-crypto-x509-test-vectors" version = "5.0.5" dependencies = [ "cargo-emit", - "clap 4.1.11", + "clap 4.1.14", "mc-crypto-keys", "mc-util-build-script", "pem", @@ -3407,7 +3413,7 @@ dependencies = [ name = "mc-fog-distribution" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "crossbeam-channel", "curve25519-dalek", "grpcio", @@ -3465,7 +3471,7 @@ name = "mc-fog-ingest-client" version = "5.0.5" dependencies = [ "assert_cmd", - "clap 4.1.11", + "clap 4.1.14", "displaydoc", "grpcio", "hex", @@ -3620,7 +3626,7 @@ dependencies = [ name = "mc-fog-ingest-server" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "dirs", "displaydoc", "futures", @@ -3842,7 +3848,7 @@ name = "mc-fog-ledger-server" version = "5.0.5" dependencies = [ "aes-gcm", - "clap 4.1.11", + "clap 4.1.14", "displaydoc", "futures", "grpcio", @@ -3924,7 +3930,7 @@ dependencies = [ name = "mc-fog-load-testing" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "grpcio", "mc-account-keys", "mc-blockchain-test-utils", @@ -3996,7 +4002,7 @@ dependencies = [ name = "mc-fog-overseer-server" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "displaydoc", "grpcio", "lazy_static", @@ -4079,7 +4085,7 @@ name = "mc-fog-report-cli" version = "5.0.5" dependencies = [ "base64 0.21.0", - "clap 4.1.11", + "clap 4.1.14", "grpcio", "hex", "mc-account-keys", @@ -4134,7 +4140,7 @@ dependencies = [ name = "mc-fog-report-server" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "displaydoc", "futures", "grpcio", @@ -4202,7 +4208,7 @@ name = "mc-fog-sample-paykit" version = "5.0.5" dependencies = [ "cargo-emit", - "clap 4.1.11", + "clap 4.1.14", "displaydoc", "futures", "grpcio", @@ -4300,7 +4306,7 @@ name = "mc-fog-sql-recovery-db" version = "5.0.5" dependencies = [ "chrono", - "clap 4.1.11", + "clap 4.1.14", "diesel", "diesel-derive-enum", "diesel_migrations", @@ -4333,7 +4339,7 @@ name = "mc-fog-sql-recovery-db-cleanup" version = "5.0.5" dependencies = [ "chrono", - "clap 4.1.11", + "clap 4.1.14", "mc-common", "mc-fog-recovery-db-iface", "mc-fog-sql-recovery-db", @@ -4344,7 +4350,7 @@ dependencies = [ name = "mc-fog-test-client" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "displaydoc", "grpcio", "hex_fmt", @@ -4378,7 +4384,7 @@ dependencies = [ name = "mc-fog-test-infra" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "digest 0.10.6", "hex", "mc-account-keys", @@ -4571,7 +4577,7 @@ dependencies = [ name = "mc-fog-view-load-test" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "grpcio", "mc-account-keys", "mc-attest-verifier", @@ -4613,7 +4619,7 @@ dependencies = [ name = "mc-fog-view-server" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "displaydoc", "futures", "grpcio", @@ -4723,7 +4729,7 @@ dependencies = [ name = "mc-ledger-distribution" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "dirs", "displaydoc", "mc-api", @@ -4746,7 +4752,7 @@ dependencies = [ name = "mc-ledger-from-archive" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "mc-api", "mc-common", "mc-ledger-db", @@ -4757,7 +4763,7 @@ dependencies = [ name = "mc-ledger-migration" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "lmdb-rkv", "mc-common", "mc-ledger-db", @@ -4805,7 +4811,7 @@ name = "mc-mobilecoind" version = "5.0.5" dependencies = [ "aes-gcm", - "clap 4.1.11", + "clap 4.1.14", "crossbeam-channel", "displaydoc", "grpcio", @@ -4893,7 +4899,7 @@ name = "mc-mobilecoind-dev-faucet" version = "5.0.5" dependencies = [ "async-channel", - "clap 4.1.11", + "clap 4.1.14", "displaydoc", "grpcio", "hex", @@ -4924,7 +4930,7 @@ dependencies = [ name = "mc-mobilecoind-json" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "grpcio", "hex", "mc-api", @@ -5104,7 +5110,7 @@ dependencies = [ name = "mc-sgx-css-dump" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "hex_fmt", "mc-sgx-css", ] @@ -5390,7 +5396,7 @@ name = "mc-transaction-signer" version = "5.0.5" dependencies = [ "anyhow", - "clap 4.1.11", + "clap 4.1.14", "displaydoc", "hex", "log", @@ -5419,15 +5425,19 @@ name = "mc-transaction-summary" version = "5.0.5" dependencies = [ "displaydoc", + "heapless", "mc-account-keys", "mc-core", "mc-crypto-digestible", "mc-crypto-keys", "mc-crypto-ring-signature", + "mc-transaction-core", "mc-transaction-types", + "mc-util-from-random", "mc-util-vec-map", "mc-util-zip-exact", "prost", + "rand", "serde", "subtle", "zeroize", @@ -5456,7 +5466,7 @@ dependencies = [ name = "mc-util-b58-decoder" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "hex", "mc-account-keys", "mc-api", @@ -5520,7 +5530,7 @@ dependencies = [ name = "mc-util-cli" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "mc-util-build-info", ] @@ -5528,7 +5538,7 @@ dependencies = [ name = "mc-util-dump-ledger" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "displaydoc", "mc-blockchain-types", "mc-common", @@ -5563,7 +5573,7 @@ dependencies = [ name = "mc-util-generate-sample-ledger" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "mc-account-keys", "mc-blockchain-test-utils", "mc-common", @@ -5583,7 +5593,7 @@ name = "mc-util-grpc" version = "5.0.5" dependencies = [ "base64 0.21.0", - "clap 4.1.11", + "clap 4.1.14", "cookie 0.17.0", "displaydoc", "futures", @@ -5616,7 +5626,7 @@ dependencies = [ name = "mc-util-grpc-admin-tool" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "grpcio", "mc-common", "mc-util-grpc", @@ -5627,7 +5637,7 @@ dependencies = [ name = "mc-util-grpc-token-generator" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "mc-common", "mc-util-grpc", "mc-util-parse", @@ -5643,7 +5653,7 @@ name = "mc-util-keyfile" version = "5.0.5" dependencies = [ "base64 0.21.0", - "clap 4.1.11", + "clap 4.1.14", "displaydoc", "hex", "mc-account-keys", @@ -5731,7 +5741,7 @@ dependencies = [ name = "mc-util-seeded-ed25519-key-gen" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "mc-crypto-keys", "mc-util-from-random", "mc-util-parse", @@ -5767,7 +5777,7 @@ dependencies = [ name = "mc-util-test-helper" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "itertools", "lazy_static", "mc-account-keys", @@ -5849,7 +5859,7 @@ dependencies = [ name = "mc-watcher" version = "5.0.5" dependencies = [ - "clap 4.1.11", + "clap 4.1.14", "displaydoc", "futures", "grpcio", @@ -6237,6 +6247,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "ordered-float" version = "1.1.1" @@ -7449,9 +7465,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.159" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" dependencies = [ "serde_derive", ] @@ -7477,9 +7493,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.159" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", @@ -8660,21 +8676,51 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", + "windows_aarch64_gnullvm 0.42.0", "windows_aarch64_msvc 0.42.0", "windows_i686_gnu 0.42.0", "windows_i686_msvc 0.42.0", "windows_x86_64_gnu 0.42.0", - "windows_x86_64_gnullvm", + "windows_x86_64_gnullvm 0.42.0", "windows_x86_64_msvc 0.42.0", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + [[package]] name = "windows_aarch64_msvc" version = "0.36.1" @@ -8687,6 +8733,12 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + [[package]] name = "windows_i686_gnu" version = "0.36.1" @@ -8699,6 +8751,12 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + [[package]] name = "windows_i686_msvc" version = "0.36.1" @@ -8711,6 +8769,12 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + [[package]] name = "windows_x86_64_gnu" version = "0.36.1" @@ -8723,12 +8787,24 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + [[package]] name = "windows_x86_64_msvc" version = "0.36.1" @@ -8741,6 +8817,12 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + [[package]] name = "winnow" version = "0.4.0" diff --git a/transaction/summary/src/report.rs b/transaction/summary/src/report.rs index 402e9361cd..926dbda554 100644 --- a/transaction/summary/src/report.rs +++ b/transaction/summary/src/report.rs @@ -35,12 +35,15 @@ pub enum TransactionEntity { // is particularly useful for eliding generics when using this and is expected // to be helpful when building support for account info caching.) pub trait TransactionReport { - /// Add value to the transaction running transaction totals - fn total_add(&mut self, amount: Amount) -> Result<(), Error>; + /// Add value to the running transaction totals + fn input_add(&mut self, amount: Amount) -> Result<(), Error>; - /// Add matched change outputs to the report, these are subtracted from the - /// transaction totals - fn change_add(&mut self, amount: Amount) -> Result<(), Error>; + /// Subtract an amount from the transaction total, used for change outputs + /// and SCIs if enabled + fn change_sub(&mut self, amount: Amount) -> Result<(), Error>; + + /// Add SCI input not owned by our account + fn sci_add(&mut self, _amount: Amount) -> Result<(), Error>; /// Add output value for a particular entity / address to the report fn output_add(&mut self, entity: TransactionEntity, amount: Amount) -> Result<(), Error>; @@ -57,12 +60,16 @@ pub trait TransactionReport { /// [TransactionReport] impl for `&mut T` where `T: TransactionReport` impl TransactionReport for &mut T { - fn total_add(&mut self, amount: Amount) -> Result<(), Error> { - ::total_add(self, amount) + fn input_add(&mut self, amount: Amount) -> Result<(), Error> { + ::input_add(self, amount) + } + + fn change_sub(&mut self, amount: Amount) -> Result<(), Error> { + ::change_sub(self, amount) } - fn change_add(&mut self, amount: Amount) -> Result<(), Error> { - ::change_add(self, amount) + fn sci_add(&mut self, amount: Amount) -> Result<(), Error> { + ::sci_add(self, amount) } fn output_add(&mut self, entity: TransactionEntity, amount: Amount) -> Result<(), Error> { @@ -97,6 +104,8 @@ pub const MAX_TOTALS: usize = 4; /// This uses a double-entry approach where outputs and totals should be /// balanced. For each token, totals = our inputs - sum(change outputs) == /// sum(other outputs) + fee +/// +/// SCI inputs are currently ignored #[derive(Clone, Debug, Default)] pub struct TxSummaryUnblindingReport< const RECORDS: usize = MAX_RECORDS, @@ -112,7 +121,7 @@ pub struct TxSummaryUnblindingReport< /// /// Note that swap inputs are elided as these are not inputs /// owned by us (ie. are not spent from our account) - pub totals: Vec<(TokenId, i64), TOTALS>, + pub totals: Vec<(TokenId, TotalKind, i64), TOTALS>, /// The network fee that we pay to execute the transaction pub network_fee: Amount, @@ -121,24 +130,36 @@ pub struct TxSummaryUnblindingReport< pub tombstone_block: u64, } +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub enum TotalKind { + /// Input owned by our account + Ours, + /// Input owned by SCI counterparty + Sci, +} + impl TransactionReport for TxSummaryUnblindingReport { - /// Add input, added to the transaction total - fn total_add(&mut self, amount: Amount) -> Result<(), Error> { + /// Add owned input, added to the transaction total + fn input_add(&mut self, amount: Amount) -> Result<(), Error> { let Amount { token_id, value } = amount; // Ensure value will not overflow let value = i64::try_from(value).map_err(|_| Error::NumericOverflow)?; // Check for existing total entry for this token - match self.totals.iter_mut().find(|(t, _)| t == &token_id) { + match self + .totals + .iter_mut() + .find(|(t, k, _)| t == &token_id && *k == TotalKind::Ours) + { // If we have an entry, add the value to this - Some(v) => v.1 = v.1.checked_add(value).ok_or(Error::NumericOverflow)?, + Some(v) => v.2 = v.2.checked_add(value).ok_or(Error::NumericOverflow)?, // If we do not, create a new entry None => self .totals - .push((token_id, value)) + .push((token_id, TotalKind::Ours, value)) .map_err(|_| Error::BufferOverflow)?, } @@ -146,26 +167,54 @@ impl TransactionReport } /// Add change output, subtracted from the transaction total - fn change_add(&mut self, amount: Amount) -> Result<(), Error> { + fn change_sub(&mut self, amount: Amount) -> Result<(), Error> { let Amount { token_id, value } = amount; // Ensure value will not overflow let value = i64::try_from(value).map_err(|_| Error::NumericOverflow)?; // Check for existing total entry for this token - match self.totals.iter_mut().find(|(t, _)| t == &token_id) { + match self + .totals + .iter_mut() + .find(|(t, k, _)| t == &token_id && *k == TotalKind::Ours) + { // If we have an entry, subtract the change value from this - Some(v) => v.1 = v.1.checked_sub(value).ok_or(Error::NumericOverflow)?, + Some(v) => v.2 = v.2.checked_sub(value).ok_or(Error::NumericOverflow)?, // If we do not, create a new entry None => self .totals - .push((token_id, -value)) + .push((token_id, TotalKind::Ours, -value)) .map_err(|_| Error::BufferOverflow)?, } Ok(()) } + /// Add SCI (or other) input not owned by our account + fn sci_add(&mut self, amount: Amount) -> Result<(), Error> { + let Amount { token_id, value } = amount; + + // Ensure value will not overflow + let value = i64::try_from(value).map_err(|_| Error::NumericOverflow)?; + + // Check for existing total entry for this token + match self + .totals + .iter_mut() + .find(|(t, k, _)| t == &token_id && *k == TotalKind::Sci) + { + // If we have an entry, add the value to this + Some(v) => v.2 = v.2.checked_add(value).ok_or(Error::NumericOverflow)?, + // If we do not, create a new entry + None => self + .totals + .push((token_id, TotalKind::Sci, value)) + .map_err(|_| Error::BufferOverflow)?, + } + Ok(()) + } + /// Add output value to a particular entity / address to the report fn output_add(&mut self, entity: TransactionEntity, amount: Amount) -> Result<(), Error> { let Amount { token_id, value } = amount; @@ -202,18 +251,41 @@ impl TransactionReport Ok(()) } - /// Finalise report, checking totals and sorting report entries + /// Finalise report, checking and balancing totals and sorting report + /// entries fn finalize(&mut self) -> Result<(), Error> { // Sort outputs and totals self.sort(); // For each token id, check that inputs match outputs - for (token_id, value) in &self.totals { + // (this is only executed where _totals_ exist, so skipped + // for the current SCI implementation) + for (token_id, total_kind, value) in &mut self.totals { // Sum outputs for this token id let mut balance = 0u64; - for (_e, id, v) in &self.outputs { - if id == token_id { - balance = balance.checked_add(*v).ok_or(Error::NumericOverflow)?; + for (e, id, v) in &self.outputs { + // Skip other tokens + if id != token_id { + continue; + } + + // Handle balance / values depending on whether the total is from us or a swap + // counterparty + match total_kind { + // If it's coming from our account, track total balance + TotalKind::Ours => { + balance = balance.checked_add(*v).ok_or(Error::NumericOverflow)?; + } + // If it's coming from an SCI, and returned to the counterparty, reduce total by + // outgoing value + TotalKind::Sci if e == &TransactionEntity::Swap => { + *value = value.checked_sub(*v as i64).ok_or(Error::NumericOverflow)?; + } + // If it's coming from an SCI to us, add to total balance + TotalKind::Sci if e != &TransactionEntity::Swap => { + balance = balance.checked_add(*v).ok_or(Error::NumericOverflow)?; + } + _ => (), } } @@ -251,10 +323,11 @@ impl TxSummaryUnblindingReport(), 1384); + assert_eq!(core::mem::size_of::(), 1416); } #[test] @@ -304,28 +377,34 @@ mod tests { ]; for a in amounts { - report.total_add(a).unwrap(); + report.input_add(a).unwrap(); } // Check total inputs report.sort(); assert_eq!( &report.totals[..], - &[(TokenId::from(1), 100), (TokenId::from(2), 300)] + &[ + (TokenId::from(1), TotalKind::Ours, 100), + (TokenId::from(2), TotalKind::Ours, 300) + ] ); // Subtract change amounts report - .change_add(Amount::new(25, TokenId::from(1))) + .change_sub(Amount::new(25, TokenId::from(1))) .unwrap(); report - .change_add(Amount::new(50, TokenId::from(2))) + .change_sub(Amount::new(50, TokenId::from(2))) .unwrap(); // Check total inputs - change assert_eq!( &report.totals[..], - &[(TokenId::from(1), 75), (TokenId::from(2), 250)] + &[ + (TokenId::from(1), TotalKind::Ours, 75), + (TokenId::from(2), TotalKind::Ours, 250) + ] ); } diff --git a/transaction/summary/src/verifier.rs b/transaction/summary/src/verifier.rs index 17810070a4..9eb40b2bcd 100644 --- a/transaction/summary/src/verifier.rs +++ b/transaction/summary/src/verifier.rs @@ -142,7 +142,7 @@ impl TxSummaryStreamingVerifierCtx { && address.spend_public_key() == self.change_address.spend_public_key() { // If this is to our change address, subtract this from the total inputs - report.change_add(amount)?; + report.change_sub(amount)?; } else { // Otherwise, add this as an output to ourself report @@ -200,10 +200,7 @@ impl TxSummaryStreamingVerifierCtx { return Err(Error::AmountVerificationFailed); } - // Add swap output to report - // NOTE: this is not exercised as swap rings are created without a transaction - // ... does this mean the ocurrence of a swap output is invalid / doesn't need - // to be handled here? + // Add outputs to swap counterparty to the report report.output_add(TransactionEntity::Swap, unmasked_amount.into())?; } @@ -253,10 +250,11 @@ impl TxSummaryStreamingVerifierCtx { if tx_in_summary.input_rules_digest.is_empty() { // If we have no input rules digest, then this is a normal input // add this to the report total - report.total_add(tx_in_summary_unblinding_data.into())?; + report.input_add(tx_in_summary_unblinding_data.into())?; } else { // If we have input rules this is an SCI input and does not impact - // our balance + // our balance, but we _can_ track this if required + report.sci_add(tx_in_summary_unblinding_data.into())?; }; // We've now verified the tx_in_summary and added it to the report. @@ -366,7 +364,7 @@ mod tests { use rand::rngs::OsRng; - use crate::TxSummaryUnblindingReport; + use crate::{report::TotalKind, TxSummaryUnblindingReport}; use mc_account_keys::AccountKey; use mc_transaction_core::{tx::TxOut, BlockVersion}; use mc_transaction_types::TokenId; @@ -391,7 +389,7 @@ mod tests { /// Outputs produced by the transaction outputs: Vec<(OutputTarget, Amount)>, /// Totals / balances by token - totals: Vec<(TokenId, i64)>, + totals: Vec<(TokenId, TotalKind, i64)>, /// Changes produced by the transaction changes: Vec<(TransactionEntity, TokenId, u64)>, } @@ -448,7 +446,7 @@ mod tests { token_id, amount.value, )], - totals: vec![(token_id, (amount.value + fee) as i64)], + totals: vec![(token_id, TotalKind::Ours, (amount.value + fee) as i64)], }, // Output to our change address, should show no outputs with balance change = fee TxOutReportTest { @@ -463,7 +461,7 @@ mod tests { changes: vec![ //(TransactionEntity::Total, token_id, 0), ], - totals: vec![(token_id, fee as i64)], + totals: vec![(token_id, TotalKind::Ours, fee as i64)], }, // Output to someone else, should show their address and total of output + fee TxOutReportTest { @@ -474,7 +472,7 @@ mod tests { token_id, amount.value, )], - totals: vec![(token_id, (amount.value + fee) as i64)], + totals: vec![(token_id, TotalKind::Ours, (amount.value + fee) as i64)], }, // Basic SCI. consuming entire swap, inputs should not count towards totals TxOutReportTest { @@ -500,7 +498,9 @@ mod tests { ], totals: vec![ // The total is the change to _our_ balance spent during the transaction - (token_id, (10_000 + fee) as i64), + (token_id, TotalKind::Ours, (10_000 + fee) as i64), + // And the SCI input + (TokenId::from(2), TotalKind::Sci, (200) as i64), ], }, // Partial SCI @@ -530,7 +530,9 @@ mod tests { ], totals: vec![ // The total is the change to _our_ balance spent during the transaction - (token_id, (7_500 + fee) as i64), + (token_id, TotalKind::Ours, (7_500 + fee) as i64), + // And the SCI input - partial value returned + (TokenId::from(2), TotalKind::Sci, (150) as i64), ], }, ]; @@ -598,8 +600,7 @@ mod tests { associated_to_input_rules: target == &OutputTarget::Swap, }; - // Set address for normal outputs or SCIs - // TODO: do we _never_ have the output address for an SCI? + // Set address for normal outputs, not provided for SCIs let address = match target != &OutputTarget::Swap { true => Some(( ShortAddressHash::from(receive_subaddress), @@ -674,7 +675,7 @@ mod tests { report.finalize().unwrap(); // Check report totals - let totals: Vec<_> = report.totals.iter().map(|(t, v)| (*t, *v)).collect(); + let totals: Vec<_> = report.totals.iter().map(|(t, k, v)| (*t, *k, *v)).collect(); assert_eq!(&totals, &t.totals, "Total mismatch"); // Check report outputs