diff --git a/CHANGELOG.md b/CHANGELOG.md index bb5224860..f1c79099a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +## [1.0.0-rc.4](https://github.com/iotaledger/inx-chronicle/compare/v1.0.0-rc.3...v1.0.0-rc.4) (2024-01-24) + +### Features + +* **api:** explorer balance endpoint now returns `availableBalance` ([#1314](https://github.com/iotaledger/inx-chronicle/issues/1314)) ([ca605a7](https://github.com/iotaledger/inx-chronicle/commit/ca605a7e48b377c77a1064f83a1abe3a394b1315)) + +### Bug Fixes + +* **db:** consider expiration return address for ledger updates ([#1314](https://github.com/iotaledger/inx-chronicle/issues/1314)) ([ca605a7](https://github.com/iotaledger/inx-chronicle/commit/ca605a7e48b377c77a1064f83a1abe3a394b1315)) +* **db:** fix balance calculation ([#1314](https://github.com/iotaledger/inx-chronicle/issues/1314)) ([ca605a7](https://github.com/iotaledger/inx-chronicle/commit/ca605a7e48b377c77a1064f83a1abe3a394b1315)) + +## [1.0.0-rc.3](https://github.com/iotaledger/inx-chronicle/compare/v1.0.0-rc.2...v1.0.0-rc.3) (2024-01-22) + +### Miscellaneous Chores + +* **deps:** update `iota-sdk` to fix validation bug + ## [1.0.0-rc.2](https://github.com/iotaledger/inx-chronicle/compare/v1.0.0-rc.1...v1.0.0-rc.2) (2023-09-12) diff --git a/Cargo.lock b/Cargo.lock index 66ce0a0fa..fe8da8c12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,9 +54,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff" +checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f" dependencies = [ "cfg-if", "getrandom", @@ -103,9 +103,9 @@ checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "arrayref" @@ -138,7 +138,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -149,7 +149,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -213,7 +213,7 @@ dependencies = [ "http 1.0.0", "http-body 1.0.0", "http-body-util", - "hyper 1.1.0", + "hyper 1.2.0", "hyper-util", "itoa", "matchit", @@ -301,7 +301,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -443,9 +443,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "a3b1be7772ee4501dba05acbe66bb1e8760f6a6c474a36035631638e4415f130" [[package]] name = "byte-slice-cast" @@ -473,12 +473,9 @@ checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" [[package]] name = "cc" -version = "1.0.83" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "7f9fa1897e4325be0d68d48df6aa1a71ac2ed4d27723887e7754192705350730" [[package]] name = "cfg-if" @@ -529,7 +526,7 @@ dependencies = [ "hex", "humantime", "humantime-serde", - "hyper 1.1.0", + "hyper 1.2.0", "hyper-util", "influxdb", "inx", @@ -574,7 +571,7 @@ dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-targets 0.52.0", + "windows-targets 0.52.2", ] [[package]] @@ -590,9 +587,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.0" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f" +checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" dependencies = [ "clap_builder", "clap_derive", @@ -600,9 +597,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.0" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99" +checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" dependencies = [ "anstyle", "clap_lex", @@ -618,7 +615,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -776,7 +773,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -824,7 +821,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -846,7 +843,7 @@ checksum = "c5a91391accf613803c2a9bf9abccdbaa07c54b4244a5b64883f9c3c137c86be" dependencies = [ "darling_core 0.20.6", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -909,7 +906,7 @@ dependencies = [ "darling 0.20.6", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -1226,7 +1223,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -1578,9 +1575,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5aa53871fc917b1a9ed87b683a5d86db645e23acb32c2e0785a353e522fb75" +checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" dependencies = [ "bytes", "futures-channel", @@ -1592,6 +1589,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", + "smallvec", "tokio", ] @@ -1631,7 +1629,7 @@ dependencies = [ "futures-util", "http 1.0.0", "http-body 1.0.0", - "hyper 1.1.0", + "hyper 1.2.0", "pin-project-lite", "socket2 0.5.5", "tokio", @@ -1768,7 +1766,7 @@ checksum = "6ac96b3660efd0cde32b0b20bc86cc93f33269cd9f6c97e759e0b0259b2133fb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -1784,7 +1782,7 @@ dependencies = [ [[package]] name = "inx" version = "2.0.0" -source = "git+https://github.com/iotaledger/inx#a6dd0abaab8d70108d5d098eddbcdfacc416f16e" +source = "git+https://github.com/iotaledger/inx#6d5f4ef12ac514f5b267ae73764fb596d57d7371" dependencies = [ "prost", "tonic", @@ -1828,7 +1826,7 @@ dependencies = [ [[package]] name = "iota-sdk" version = "1.1.4" -source = "git+https://github.com/iotaledger/iota-sdk?branch=2.0#9db8a1c89c0eee4a3545dca92770012de4bcfea4" +source = "git+https://github.com/iotaledger/iota-sdk?branch=2.0#4077c17fb940325cc4b84190fcf13b088811aebd" dependencies = [ "bech32", "bitflags 2.4.2", @@ -2382,7 +2380,7 @@ checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -2482,7 +2480,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" dependencies = [ "proc-macro2", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -2577,7 +2575,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.48", + "syn 2.0.50", "tempfile", "which", ] @@ -2592,7 +2590,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -2823,16 +2821,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", "spin 0.9.8", "untrusted 0.9.0", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2885,7 +2884,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.21", + "semver 1.0.22", ] [[package]] @@ -2918,7 +2917,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", - "ring 0.17.7", + "ring 0.17.8", "rustls-webpki", "sct", ] @@ -2938,7 +2937,7 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] @@ -2950,9 +2949,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "salsa20" @@ -2995,7 +2994,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] @@ -3025,9 +3024,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "semver-parser" @@ -3037,9 +3036,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] @@ -3055,20 +3054,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "serde_json" -version = "1.0.113" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "indexmap 2.2.3", "itoa", @@ -3094,7 +3093,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -3359,7 +3358,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -3381,9 +3380,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" dependencies = [ "proc-macro2", "quote", @@ -3468,14 +3467,14 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", @@ -3574,7 +3573,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -3678,7 +3677,7 @@ dependencies = [ "proc-macro2", "prost-build", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -3750,7 +3749,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -3887,9 +3886,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] @@ -3995,7 +3994,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", "wasm-bindgen-shared", ] @@ -4029,7 +4028,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4124,7 +4123,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.2", ] [[package]] @@ -4142,7 +4141,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.2", ] [[package]] @@ -4162,17 +4161,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "d98532992affa02e52709d5b4d145a3668ae10d9081eea4a7f26f719a8476f71" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.1", + "windows_aarch64_msvc 0.52.1", + "windows_i686_gnu 0.52.1", + "windows_i686_msvc 0.52.1", + "windows_x86_64_gnu 0.52.1", + "windows_x86_64_gnullvm 0.52.1", + "windows_x86_64_msvc 0.52.1", ] [[package]] @@ -4183,9 +4182,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "e7269c1442e75af9fa59290383f7665b828efc76c429cc0b7f2ecb33cf51ebae" [[package]] name = "windows_aarch64_msvc" @@ -4201,9 +4200,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "f70ab2cebf332b7ecbdd98900c2da5298a8c862472fb35c75fc297eabb9d89b8" [[package]] name = "windows_i686_gnu" @@ -4219,9 +4218,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "679f235acf6b1639408c0f6db295697a19d103b0cdc88146aa1b992c580c647d" [[package]] name = "windows_i686_msvc" @@ -4237,9 +4236,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "3480ac194b55ae274a7e135c21645656825da4a7f5b6e9286291b2113c94a78b" [[package]] name = "windows_x86_64_gnu" @@ -4255,9 +4254,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "42c46bab241c121402d1cb47d028ea3680ee2f359dcc287482dcf7fdddc73363" [[package]] name = "windows_x86_64_gnullvm" @@ -4267,9 +4266,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "dc885a4332ee1afb9a1bacf11514801011725570d35675abc229ce7e3afe4d20" [[package]] name = "windows_x86_64_msvc" @@ -4285,9 +4284,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "9e440c60457f84b0bee09208e62acc7ade264b38c4453f6312b8c9ab1613e73c" [[package]] name = "winnow" @@ -4351,7 +4350,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -4372,5 +4371,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] diff --git a/documentation/api/api-explorer.yml b/documentation/api/api-explorer.yml index 55e4b504b..9084a2f34 100644 --- a/documentation/api/api-explorer.yml +++ b/documentation/api/api-explorer.yml @@ -275,16 +275,30 @@ components: totalBalance: type: string description: >- - The total value held in unspent outputs owned by the given address - (includes funds held in storage deposit). - sigLockedBalance: + The total balance held in unspent outputs that is unlockable by the given address or currently timelocked. + Does not include funds held in storage deposit. + availableBalance: type: string description: >- - The sum of value held in unspent outputs owned by the given address - that are signature locked ("trivially unlockable"). + The total balance held in unspent outputs that is immediately unlockable at ledgerIndex by the given address. + Does not include funds held in storage deposit. ledgerIndex: type: integer - description: The ledger index for which the balance calculation was performed. + description: The slot index for which the balance calculation was performed. + Balance: + description: Balance of IOTA tokens and mana. + properties: + amount: + type: string + description: The amount of IOTA tokens. + mana: + properties: + stored: + type: string + description: The amount of stored mana with decay. + potential: + type: string + description: The amount of potential mana with decay. BlockChildrenResponse: description: Returns the children of a given block. properties: @@ -584,8 +598,16 @@ components: examples: balance-example: value: - totalBalance: 100000 - sigLockedBalance: 99900 + totalBalance: + amount: 100000 + mana: + stored: 100 + potential: 12345 + availableBalance: + amount: 99990 + mana: + stored: 200 + potential: 23455 ledgerIndex: 500000 ledger-updates-address-example: value: diff --git a/src/analytics/ledger/active_addresses.rs b/src/analytics/ledger/active_addresses.rs index 22845d8b2..a57e11d4f 100644 --- a/src/analytics/ledger/active_addresses.rs +++ b/src/analytics/ledger/active_addresses.rs @@ -66,18 +66,14 @@ impl Analytics for AddressActivityAnalytics { _payload: &SignedTransactionPayload, consumed: &[LedgerSpent], created: &[LedgerOutput], - _ctx: &dyn AnalyticsContext, + ctx: &dyn AnalyticsContext, ) { for output in consumed { - if let Some(a) = output.address() { - self.add_address(a); - } + self.add_address(output.locked_address_at(ctx.slot_index(), ctx.protocol_parameters())); } for output in created { - if let Some(a) = output.address() { - self.add_address(a); - } + self.add_address(output.locked_address_at(ctx.slot_index(), ctx.protocol_parameters())); } } @@ -93,22 +89,22 @@ impl Analytics for AddressActivityAnalytics { } impl AddressActivityAnalytics { - fn add_address(&mut self, address: &Address) { + fn add_address(&mut self, address: Address) { match address { Address::Ed25519(a) => { - self.ed25519_addresses.insert(*a); + self.ed25519_addresses.insert(a); } Address::Account(a) => { - self.account_addresses.insert(*a); + self.account_addresses.insert(a); } Address::Nft(a) => { - self.nft_addresses.insert(*a); + self.nft_addresses.insert(a); } Address::Anchor(a) => { - self.anchor_addresses.insert(*a); + self.anchor_addresses.insert(a); } Address::ImplicitAccountCreation(a) => { - self.implicit_addresses.insert(*a); + self.implicit_addresses.insert(a); } _ => (), } diff --git a/src/analytics/ledger/address_balance.rs b/src/analytics/ledger/address_balance.rs index 2c5914ae2..c100a2e29 100644 --- a/src/analytics/ledger/address_balance.rs +++ b/src/analytics/ledger/address_balance.rs @@ -6,6 +6,8 @@ use std::collections::HashMap; use iota_sdk::types::block::{ address::{AccountAddress, Address, AnchorAddress, Ed25519Address, ImplicitAccountCreationAddress, NftAddress}, payload::SignedTransactionPayload, + protocol::ProtocolParameters, + slot::SlotIndex, }; use serde::{Deserialize, Serialize}; @@ -51,23 +53,25 @@ pub(crate) struct AddressBalancesAnalytics { impl AddressBalancesAnalytics { /// Initialize the analytics by reading the current ledger state. - pub(crate) fn init<'a>(unspent_outputs: impl IntoIterator) -> Self { + pub(crate) fn init<'a>( + protocol_parameters: &ProtocolParameters, + slot: SlotIndex, + unspent_outputs: impl IntoIterator, + ) -> Self { let mut balances = AddressBalancesAnalytics::default(); for output in unspent_outputs { - if let Some(a) = output.address() { - balances.add_address(a, output.amount()); - } + balances.add_address(output.locked_address_at(slot, protocol_parameters), output.amount()); } balances } - fn add_address(&mut self, address: &Address, output_amount: u64) { + fn add_address(&mut self, address: Address, output_amount: u64) { match address { - Address::Ed25519(a) => *self.ed25519_balances.entry(*a).or_default() += output_amount, - Address::Account(a) => *self.account_balances.entry(*a).or_default() += output_amount, - Address::Nft(a) => *self.nft_balances.entry(*a).or_default() += output_amount, - Address::Anchor(a) => *self.anchor_balances.entry(*a).or_default() += output_amount, - Address::ImplicitAccountCreation(a) => *self.implicit_balances.entry(*a).or_default() += output_amount, + Address::Ed25519(a) => *self.ed25519_balances.entry(a).or_default() += output_amount, + Address::Account(a) => *self.account_balances.entry(a).or_default() += output_amount, + Address::Nft(a) => *self.nft_balances.entry(a).or_default() += output_amount, + Address::Anchor(a) => *self.anchor_balances.entry(a).or_default() += output_amount, + Address::ImplicitAccountCreation(a) => *self.implicit_balances.entry(a).or_default() += output_amount, _ => (), } } @@ -127,18 +131,20 @@ impl Analytics for AddressBalancesAnalytics { _payload: &SignedTransactionPayload, consumed: &[LedgerSpent], created: &[LedgerOutput], - _ctx: &dyn AnalyticsContext, + ctx: &dyn AnalyticsContext, ) { for output in consumed { - if let Some(address) = output.address() { - self.remove_amount(address, output.amount()); - } + self.remove_amount( + &output.locked_address_at(ctx.slot_index(), ctx.protocol_parameters()), + output.amount(), + ); } for output in created { - if let Some(address) = output.address() { - self.add_address(address, output.amount()) - } + self.add_address( + output.locked_address_at(ctx.slot_index(), ctx.protocol_parameters()), + output.amount(), + ) } } diff --git a/src/analytics/ledger/base_token.rs b/src/analytics/ledger/base_token.rs index 511ccaaf5..965ad5a67 100644 --- a/src/analytics/ledger/base_token.rs +++ b/src/analytics/ledger/base_token.rs @@ -3,10 +3,7 @@ use std::collections::HashMap; -use iota_sdk::types::block::{ - address::{Bech32Address, ToBech32Ext}, - payload::SignedTransactionPayload, -}; +use iota_sdk::types::block::{address::Address, payload::SignedTransactionPayload}; use crate::{ analytics::{Analytics, AnalyticsContext}, @@ -33,25 +30,24 @@ impl Analytics for BaseTokenActivityMeasurement { created: &[LedgerOutput], ctx: &dyn AnalyticsContext, ) { - let hrp = ctx.protocol_parameters().bech32_hrp(); // The idea behind the following code is that we keep track of the deltas that are applied to each account that // is represented by an address. - let mut balance_deltas: HashMap = HashMap::new(); + let mut balance_deltas: HashMap = HashMap::new(); // We first gather all tokens that have been moved to an individual address. for output in created { - if let Some(a) = output.address() { - *balance_deltas.entry(a.clone().to_bech32(hrp)).or_default() += output.amount() as i128; - } + *balance_deltas + .entry(output.locked_address_at(ctx.slot_index(), ctx.protocol_parameters())) + .or_default() += output.amount() as i128; } self.booked_amount += balance_deltas.values().sum::() as u64; // Afterwards, we subtract the tokens from that address to get the actual deltas of each account. for output in consumed { - if let Some(a) = output.address() { - *balance_deltas.entry(a.clone().to_bech32(hrp)).or_default() -= output.amount() as i128; - } + *balance_deltas + .entry(output.locked_address_at(ctx.slot_index(), ctx.protocol_parameters())) + .or_default() -= output.amount() as i128; } // The number of transferred tokens is then the sum of all deltas. diff --git a/src/analytics/mod.rs b/src/analytics/mod.rs index e34aa1e11..91569e60e 100644 --- a/src/analytics/mod.rs +++ b/src/analytics/mod.rs @@ -160,12 +160,15 @@ impl Analytic { /// Init an analytic from a choice and ledger state. pub fn init<'a>( choice: &AnalyticsChoice, + slot: SlotIndex, protocol_params: &ProtocolParameters, unspent_outputs: impl IntoIterator, ) -> Self { Self(match choice { // Need ledger state - AnalyticsChoice::AddressBalance => Box::new(AddressBalancesAnalytics::init(unspent_outputs)) as _, + AnalyticsChoice::AddressBalance => { + Box::new(AddressBalancesAnalytics::init(protocol_params, slot, unspent_outputs)) as _ + } AnalyticsChoice::Features => Box::new(FeaturesMeasurement::init(unspent_outputs)) as _, AnalyticsChoice::LedgerOutputs => Box::new(LedgerOutputMeasurement::init(unspent_outputs)) as _, AnalyticsChoice::LedgerSize => Box::new(LedgerSizeAnalytics::init(protocol_params, unspent_outputs)) as _, diff --git a/src/bin/inx-chronicle/api/explorer/responses.rs b/src/bin/inx-chronicle/api/explorer/responses.rs index 5be468cb8..cd4eeba2d 100644 --- a/src/bin/inx-chronicle/api/explorer/responses.rs +++ b/src/bin/inx-chronicle/api/explorer/responses.rs @@ -121,7 +121,6 @@ pub struct BlockPayloadTypeDto { #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct BlocksBySlotResponse { - pub count: usize, pub blocks: Vec, pub cursor: Option, } diff --git a/src/bin/inx-chronicle/cli/analytics.rs b/src/bin/inx-chronicle/cli/analytics.rs index 58c75b345..99f1c77f4 100644 --- a/src/bin/inx-chronicle/cli/analytics.rs +++ b/src/bin/inx-chronicle/cli/analytics.rs @@ -10,12 +10,13 @@ use chronicle::{ config::{all_analytics, all_interval_analytics, IntervalAnalyticsChoice}, AnalyticsChoice, InfluxDb, }, - mongodb::collections::{ApplicationStateCollection, OutputCollection}, + mongodb::collections::{ApplicationStateCollection, CommittedSlotCollection, OutputCollection}, MongoDb, }, tangle::{InputSource, Tangle}, }; use clap::Parser; +use eyre::OptionExt; use futures::TryStreamExt; use iota_sdk::types::block::slot::SlotIndex; use time::{Date, OffsetDateTime}; @@ -106,7 +107,11 @@ impl FillAnalyticsCommand { protocol_params.slot_duration_in_seconds(), ) } else { - todo!("get the oldest slot in the DB") + db.collection::() + .get_earliest_committed_slot() + .await? + .ok_or_eyre("no slots in database")? + .slot_index }; let (start_index, start_date) = ( start_index, @@ -135,7 +140,11 @@ impl FillAnalyticsCommand { protocol_params.slot_duration_in_seconds(), ) } else { - todo!("get the newest slot in the DB") + db.collection::() + .get_latest_committed_slot() + .await? + .ok_or_eyre("no slots in database")? + .slot_index }; let (end_index, end_date) = ( end_index, @@ -257,7 +266,7 @@ pub async fn fill_analytics( state = Some( analytics_choices .iter() - .map(|choice| Analytic::init(choice, &protocol_params, &ledger_state)) + .map(|choice| Analytic::init(choice, slot.index(), &protocol_params, &ledger_state)) .collect(), ); } diff --git a/src/bin/inx-chronicle/inx/influx/analytics.rs b/src/bin/inx-chronicle/inx/influx/analytics.rs index 4c72e403b..00b2a22f5 100644 --- a/src/bin/inx-chronicle/inx/influx/analytics.rs +++ b/src/bin/inx-chronicle/inx/influx/analytics.rs @@ -73,7 +73,7 @@ impl InxWorker { *state = Some( analytics_choices .iter() - .map(|choice| Analytic::init(choice, protocol_params, &ledger_state)) + .map(|choice| Analytic::init(choice, slot.index(), protocol_params, &ledger_state)) .collect(), ); } diff --git a/src/bin/inx-chronicle/inx/mod.rs b/src/bin/inx-chronicle/inx/mod.rs index 337c13b68..40e173e31 100644 --- a/src/bin/inx-chronicle/inx/mod.rs +++ b/src/bin/inx-chronicle/inx/mod.rs @@ -22,7 +22,7 @@ use chronicle::{ }; use eyre::{bail, Result}; use futures::{StreamExt, TryStreamExt}; -use iota_sdk::types::block::{output::StorageScoreParameters, protocol::ProtocolParameters, slot::SlotIndex}; +use iota_sdk::types::block::{protocol::ProtocolParameters, slot::SlotIndex}; use tokio::{task::JoinSet, try_join}; use tracing::{debug, info, instrument, trace_span, Instrument}; @@ -185,7 +185,7 @@ impl InxWorker { .await?; let mut starting_index = None; - let protocol_params = node_configuration.latest_parameters(); + let protocol_parameters = node_configuration.latest_parameters(); let mut count = 0; let mut tasks = unspent_output_stream @@ -212,8 +212,8 @@ impl InxWorker { // Convert batches to tasks .try_fold(JoinSet::new(), |mut tasks, batch| async { let db = self.db.clone(); - let params = protocol_params.storage_score_parameters(); - tasks.spawn(async move { insert_unspent_outputs(&db, &batch, params).await }); + let protocol_parameters = protocol_parameters.clone(); + tasks.spawn(async move { insert_unspent_outputs(&db, &batch, &protocol_parameters).await }); Result::<_>::Ok(tasks) }) .await?; @@ -228,8 +228,8 @@ impl InxWorker { // Get the timestamp for the starting index let slot_timestamp = starting_index.to_timestamp( - protocol_params.genesis_unix_timestamp(), - protocol_params.slot_duration_in_seconds(), + protocol_parameters.genesis_unix_timestamp(), + protocol_parameters.slot_duration_in_seconds(), ); info!( @@ -247,7 +247,7 @@ impl InxWorker { info!( "Linking database `{}` to network `{}`.", self.db.name(), - protocol_params.network_name() + protocol_parameters.network_name() ); } @@ -279,15 +279,15 @@ impl InxWorker { for batch in slot.ledger_updates().created_outputs().chunks(INSERT_BATCH_SIZE) { let db = self.db.clone(); let batch = batch.to_vec(); - let params = protocol_parameters.storage_score_parameters(); - tasks.spawn(async move { insert_unspent_outputs(&db, &batch, params).await }); + let protocol_parameters = protocol_parameters.clone(); + tasks.spawn(async move { insert_unspent_outputs(&db, &batch, &protocol_parameters).await }); } for batch in slot.ledger_updates().consumed_outputs().chunks(INSERT_BATCH_SIZE) { let db = self.db.clone(); let batch = batch.to_vec(); - let params = protocol_parameters.storage_score_parameters(); - tasks.spawn(async move { update_spent_outputs(&db, &batch, params).await }); + let protocol_parameters = protocol_parameters.clone(); + tasks.spawn(async move { update_spent_outputs(&db, &batch, &protocol_parameters).await }); } while let Some(res) = tasks.join_next().await { @@ -350,7 +350,7 @@ impl InxWorker { } #[instrument(skip_all, err, fields(num = outputs.len()), level = "trace")] -async fn insert_unspent_outputs(db: &MongoDb, outputs: &[LedgerOutput], params: StorageScoreParameters) -> Result<()> { +async fn insert_unspent_outputs(db: &MongoDb, outputs: &[LedgerOutput], params: &ProtocolParameters) -> Result<()> { let output_collection = db.collection::(); let ledger_collection = db.collection::(); try_join! { @@ -359,7 +359,7 @@ async fn insert_unspent_outputs(db: &MongoDb, outputs: &[LedgerOutput], params: Result::<_>::Ok(()) }, async { - ledger_collection.insert_unspent_ledger_updates(outputs).await?; + ledger_collection.insert_unspent_ledger_updates(outputs, params).await?; Ok(()) } }?; @@ -367,7 +367,7 @@ async fn insert_unspent_outputs(db: &MongoDb, outputs: &[LedgerOutput], params: } #[instrument(skip_all, err, fields(num = outputs.len()), level = "trace")] -async fn update_spent_outputs(db: &MongoDb, outputs: &[LedgerSpent], params: StorageScoreParameters) -> Result<()> { +async fn update_spent_outputs(db: &MongoDb, outputs: &[LedgerSpent], params: &ProtocolParameters) -> Result<()> { let output_collection = db.collection::(); let ledger_collection = db.collection::(); try_join! { @@ -376,7 +376,7 @@ async fn update_spent_outputs(db: &MongoDb, outputs: &[LedgerSpent], params: Sto Ok(()) }, async { - ledger_collection.insert_spent_ledger_updates(outputs).await?; + ledger_collection.insert_spent_ledger_updates(outputs, params).await?; Ok(()) } } diff --git a/src/bin/inx-chronicle/migrations/migrate_2.rs b/src/bin/inx-chronicle/migrations/migrate_2.rs new file mode 100644 index 000000000..6875d5977 --- /dev/null +++ b/src/bin/inx-chronicle/migrations/migrate_2.rs @@ -0,0 +1,122 @@ +// Copyright 2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_trait::async_trait; +use chronicle::{ + db::{ + mongodb::collections::{LedgerUpdateCollection, OutputCollection}, + MongoDb, MongoDbCollection, MongoDbCollectionExt, + }, + model::{ + ledger::{LedgerOutput, LedgerSpent, RentStructureBytes}, + metadata::OutputMetadata, + utxo::{Output, OutputId}, + }, +}; +use futures::{prelude::stream::TryStreamExt, StreamExt}; +use mongodb::bson::doc; +use serde::Deserialize; +use tokio::{task::JoinSet, try_join}; + +use super::Migration; + +const INSERT_BATCH_SIZE: usize = 1000; + +pub struct Migrate; + +#[async_trait] +impl Migration for Migrate { + const ID: usize = 2; + const APP_VERSION: &'static str = "1.0.0-rc.3"; + const DATE: time::Date = time::macros::date!(2024 - 01 - 12); + + async fn migrate(db: &MongoDb) -> eyre::Result<()> { + db.collection::() + .collection() + .drop(None) + .await?; + + let outputs_stream = db + .collection::() + .find::(doc! {}, None) + .await?; + let mut batched_stream = outputs_stream.try_chunks(INSERT_BATCH_SIZE); + + let mut tasks = JoinSet::new(); + + while let Some(batch) = batched_stream.next().await { + let batch = batch?; + while tasks.len() >= 100 { + if let Some(res) = tasks.join_next().await { + res??; + } + } + let db = db.clone(); + tasks.spawn(async move { + let consumed = batch.iter().filter_map(Option::::from).collect::>(); + let created = batch.into_iter().map(LedgerOutput::from).collect::>(); + try_join! { + async { + db.collection::() + .insert_unspent_ledger_updates(&created) + .await + }, + async { + db.collection::().update_spent_outputs(&consumed).await + }, + async { + db.collection::().insert_spent_ledger_updates(&consumed).await + } + } + .and(Ok(())) + }); + } + + while let Some(res) = tasks.join_next().await { + res??; + } + + Ok(()) + } +} + +#[derive(Deserialize)] +pub struct OutputDocument { + #[serde(rename = "_id")] + output_id: OutputId, + output: Output, + metadata: OutputMetadata, + details: OutputDetails, +} + +#[derive(Deserialize)] +struct OutputDetails { + rent_structure: RentStructureBytes, +} + +impl From for LedgerOutput { + fn from(value: OutputDocument) -> Self { + Self { + output_id: value.output_id, + block_id: value.metadata.block_id, + booked: value.metadata.booked, + output: value.output, + rent_structure: value.details.rent_structure, + } + } +} + +impl From<&OutputDocument> for Option { + fn from(value: &OutputDocument) -> Self { + value.metadata.spent_metadata.map(|spent_metadata| LedgerSpent { + spent_metadata, + output: LedgerOutput { + output_id: value.output_id, + block_id: value.metadata.block_id, + booked: value.metadata.booked, + output: value.output.clone(), + rent_structure: value.details.rent_structure, + }, + }) + } +} diff --git a/src/db/mongodb/collections/committed_slot.rs b/src/db/mongodb/collections/committed_slot.rs index 0bd188fe4..abd919496 100644 --- a/src/db/mongodb/collections/committed_slot.rs +++ b/src/db/mongodb/collections/committed_slot.rs @@ -46,6 +46,13 @@ impl MongoDbCollection for CommittedSlotCollection { } impl CommittedSlotCollection { + /// Gets the earliest committed slot. + pub async fn get_earliest_committed_slot(&self) -> Result, DbError> { + Ok(self + .find_one(doc! {}, FindOneOptions::builder().sort(doc! { "_id": 1 }).build()) + .await?) + } + /// Gets the latest committed slot. pub async fn get_latest_committed_slot(&self) -> Result, DbError> { Ok(self diff --git a/src/db/mongodb/collections/ledger_update.rs b/src/db/mongodb/collections/ledger_update.rs index 97375118c..e0828aa5f 100644 --- a/src/db/mongodb/collections/ledger_update.rs +++ b/src/db/mongodb/collections/ledger_update.rs @@ -6,6 +6,7 @@ use iota_sdk::types::block::{ address::Address, output::{Output, OutputId}, payload::signed_transaction::TransactionId, + protocol::ProtocolParameters, slot::{SlotCommitmentId, SlotIndex}, BlockId, }; @@ -145,21 +146,25 @@ fn oldest() -> Document { impl LedgerUpdateCollection { /// Inserts spent ledger updates. #[instrument(skip_all, err, level = "trace")] - pub async fn insert_spent_ledger_updates<'a, I>(&self, outputs: I) -> Result<(), DbError> + pub async fn insert_spent_ledger_updates<'a, I>( + &self, + outputs: I, + params: &ProtocolParameters, + ) -> Result<(), DbError> where I: IntoIterator, I::IntoIter: Send + Sync, { - let ledger_updates = outputs.into_iter().filter_map(|LedgerSpent { output, .. }| { + let ledger_updates = outputs.into_iter().map(|output| { // Ledger updates - output.address().map(|address| LedgerUpdateDocument { + LedgerUpdateDocument { _id: LedgerUpdateByAddressRecord { - slot_index: output.slot_booked, - output_id: output.output_id, + slot_index: output.slot_booked(), + output_id: output.output_id(), is_spent: true, }, - address: address.into(), - }) + address: output.locked_address(params).into(), + } }); self.insert_many_ignore_duplicates(ledger_updates, InsertManyOptions::builder().ordered(false).build()) .await?; @@ -169,21 +174,25 @@ impl LedgerUpdateCollection { /// Inserts unspent ledger updates. #[instrument(skip_all, err, level = "trace")] - pub async fn insert_unspent_ledger_updates<'a, I>(&self, outputs: I) -> Result<(), DbError> + pub async fn insert_unspent_ledger_updates<'a, I>( + &self, + outputs: I, + params: &ProtocolParameters, + ) -> Result<(), DbError> where I: IntoIterator, I::IntoIter: Send + Sync, { - let ledger_updates = outputs.into_iter().filter_map(|output| { + let ledger_updates = outputs.into_iter().map(|output| { // Ledger updates - output.address().map(|address| LedgerUpdateDocument { + LedgerUpdateDocument { _id: LedgerUpdateByAddressRecord { slot_index: output.slot_booked, output_id: output.output_id, is_spent: false, }, - address: address.into(), - }) + address: output.locked_address(params).into(), + } }); self.insert_many_ignore_duplicates(ledger_updates, InsertManyOptions::builder().ordered(false).build()) .await?; diff --git a/src/db/mongodb/collections/outputs/mod.rs b/src/db/mongodb/collections/outputs/mod.rs index 82730c7b3..1be6775f9 100644 --- a/src/db/mongodb/collections/outputs/mod.rs +++ b/src/db/mongodb/collections/outputs/mod.rs @@ -9,7 +9,7 @@ use futures::{Stream, TryStreamExt}; use iota_sdk::{ types::block::{ address::Address, - output::{AccountId, MinimumOutputAmount, Output, OutputId, StorageScoreParameters}, + output::{AccountId, MinimumOutputAmount, Output, OutputId}, payload::signed_transaction::TransactionId, protocol::ProtocolParameters, slot::{SlotCommitmentId, SlotIndex}, @@ -142,8 +142,7 @@ struct OutputDetails { generation_amount: u64, #[serde(default, skip_serializing_if = "Option::is_none")] indexed_id: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - address: Option, + address: AddressDto, #[serde(default, skip_serializing_if = "Option::is_none")] governor_address: Option, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -173,7 +172,7 @@ struct OutputDetails { } impl OutputDocument { - pub fn from_ledger_output(rec: &LedgerOutput, params: StorageScoreParameters) -> Self { + pub fn from_ledger_output(rec: &LedgerOutput, params: &ProtocolParameters) -> Self { Self { output_id: rec.output_id, output: rec.output.clone(), @@ -187,7 +186,9 @@ impl OutputDocument { kind: rec.kind().to_owned(), amount: rec.amount(), stored_mana: rec.output().mana(), - generation_amount: rec.amount().saturating_sub(rec.output().minimum_amount(params)), + generation_amount: rec + .amount() + .saturating_sub(rec.output().minimum_amount(params.storage_score_parameters())), indexed_id: match rec.output() { Output::Account(output) => Some(output.account_id_non_null(&rec.output_id).into()), Output::Anchor(output) => Some(output.anchor_id_non_null(&rec.output_id).into()), @@ -196,11 +197,7 @@ impl OutputDocument { Output::Foundry(output) => Some(output.id().into()), _ => None, }, - address: rec - .output() - .unlock_conditions() - .and_then(|uc| uc.address()) - .map(|uc| uc.address().into()), + address: rec.locked_address(params).into(), governor_address: rec .output() .unlock_conditions() @@ -262,8 +259,10 @@ impl OutputDocument { } } - fn from_ledger_spent(rec: &LedgerSpent, params: StorageScoreParameters) -> Self { + fn from_ledger_spent(rec: &LedgerSpent, params: &ProtocolParameters) -> Self { let mut res = Self::from_ledger_output(&rec.output, params); + // Update the address as the spending may have changed it + res.details.address = rec.locked_address(params).into(); res.metadata.spent_metadata.replace(SpentMetadata { slot_spent: rec.slot_spent, commitment_id_spent: rec.commitment_id_spent, @@ -390,7 +389,7 @@ impl OutputCollection { pub async fn update_spent_outputs( &self, outputs: impl IntoIterator, - params: StorageScoreParameters, + params: &ProtocolParameters, ) -> Result<(), DbError> { // TODO: Replace `db.run_command` once the `BulkWrite` API lands in the Rust driver. let update_docs = outputs @@ -421,7 +420,7 @@ impl OutputCollection { /// Inserts unspent ledger outputs. #[instrument(skip_all, err, level = "trace")] - pub async fn insert_unspent_outputs(&self, outputs: I, params: StorageScoreParameters) -> Result<(), DbError> + pub async fn insert_unspent_outputs(&self, outputs: I, params: &ProtocolParameters) -> Result<(), DbError> where I: IntoIterator, I::IntoIter: Send + Sync, @@ -863,7 +862,7 @@ impl OutputCollection { } } - /// Get the address activity in a date + /// Get the address activity in a date range pub async fn get_address_activity_count_in_range( &self, start_date: time::Date, diff --git a/src/inx/ledger.rs b/src/inx/ledger.rs index 79f91b2bb..b1c88eae4 100644 --- a/src/inx/ledger.rs +++ b/src/inx/ledger.rs @@ -2,9 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 use inx::proto; -use iota_sdk::types::block::{ - payload::signed_transaction::TransactionId, - slot::{SlotCommitmentId, SlotIndex}, +use iota_sdk::types::{ + api::core::BlockFailureReason, + block::{ + payload::signed_transaction::TransactionId, + semantic::TransactionFailureReason, + slot::{SlotCommitmentId, SlotIndex}, + }, }; use super::{ @@ -14,7 +18,7 @@ use super::{ use crate::{ maybe_missing, model::{ - block_metadata::{BlockFailureReason, BlockState, TransactionFailureReason, TransactionState}, + block_metadata::{BlockState, TransactionState}, ledger::{LedgerOutput, LedgerSpent}, }, }; @@ -241,6 +245,11 @@ impl ConvertFrom for Opti ProtoState::InputAlreadySpent => TransactionFailureReason::InputAlreadySpent, ProtoState::InputCreationAfterTxCreation => TransactionFailureReason::InputCreationAfterTxCreation, ProtoState::UnlockSignatureInvalid => TransactionFailureReason::UnlockSignatureInvalid, + ProtoState::ChainAddressUnlockInvalid => TransactionFailureReason::ChainAddressUnlockInvalid, + ProtoState::DirectUnlockableAddressUnlockInvalid => { + TransactionFailureReason::DirectUnlockableAddressUnlockInvalid + } + ProtoState::MultiAddressUnlockInvalid => TransactionFailureReason::MultiAddressUnlockInvalid, ProtoState::CommitmentInputReferenceInvalid => TransactionFailureReason::CommitmentInputReferenceInvalid, ProtoState::BicInputReferenceInvalid => TransactionFailureReason::BicInputReferenceInvalid, ProtoState::RewardInputReferenceInvalid => TransactionFailureReason::RewardInputReferenceInvalid, diff --git a/src/model/block_metadata.rs b/src/model/block_metadata.rs index 25b746190..9aad05e55 100644 --- a/src/model/block_metadata.rs +++ b/src/model/block_metadata.rs @@ -3,7 +3,15 @@ //! Module containing block metadata types. -use iota_sdk::types::block::{self as iota, payload::signed_transaction::TransactionId, BlockId}; +use iota_sdk::{ + types::{ + api::core::BlockFailureReason, + block::{ + self as iota, payload::signed_transaction::TransactionId, semantic::TransactionFailureReason, BlockId, + }, + }, + utils::serde::option_string, +}; use serde::{Deserialize, Serialize}; use super::raw::Raw; @@ -13,6 +21,7 @@ use super::raw::Raw; pub struct BlockMetadata { pub block_id: BlockId, pub block_state: BlockState, + #[serde(with = "option_string")] pub block_failure_reason: Option, pub transaction_metadata: Option, } @@ -23,6 +32,7 @@ pub struct BlockMetadata { pub struct TransactionMetadata { pub transaction_id: TransactionId, pub transaction_state: TransactionState, + #[serde(with = "option_string")] pub transaction_failure_reason: Option, } @@ -94,217 +104,3 @@ impl From for iota_sdk::types::api::core::TransactionState { } } } - -/// Describes the reason of a block failure. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -#[allow(missing_docs)] -pub enum BlockFailureReason { - TooOldToIssue = 1, - ParentTooOld = 2, - ParentDoesNotExist = 3, - IssuerAccountNotFound = 4, - ManaCostCalculationFailed = 5, - BurnedInsufficientMana = 6, - AccountLocked = 7, - AccountExpired = 8, - SignatureInvalid = 9, - DroppedDueToCongestion = 10, - PayloadInvalid = 11, - Invalid = 255, -} - -impl From for iota_sdk::types::api::core::BlockFailureReason { - fn from(value: BlockFailureReason) -> Self { - match value { - BlockFailureReason::TooOldToIssue => Self::TooOldToIssue, - BlockFailureReason::ParentTooOld => Self::ParentTooOld, - BlockFailureReason::ParentDoesNotExist => Self::ParentDoesNotExist, - BlockFailureReason::IssuerAccountNotFound => Self::IssuerAccountNotFound, - BlockFailureReason::ManaCostCalculationFailed => Self::ManaCostCalculationFailed, - BlockFailureReason::BurnedInsufficientMana => Self::BurnedInsufficientMana, - BlockFailureReason::AccountLocked => Self::AccountLocked, - BlockFailureReason::AccountExpired => Self::AccountExpired, - BlockFailureReason::SignatureInvalid => Self::SignatureInvalid, - BlockFailureReason::DroppedDueToCongestion => Self::DroppedDueToCongestion, - BlockFailureReason::PayloadInvalid => Self::PayloadInvalid, - BlockFailureReason::Invalid => Self::Invalid, - } - } -} - -/// Describes the reason of a transaction failure. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -#[allow(missing_docs)] -pub enum TransactionFailureReason { - ConflictRejected = 1, - InputAlreadySpent = 2, - InputCreationAfterTxCreation = 3, - UnlockSignatureInvalid = 4, - CommitmentInputReferenceInvalid = 5, - BicInputReferenceInvalid = 6, - RewardInputReferenceInvalid = 7, - StakingRewardCalculationFailure = 8, - DelegationRewardCalculationFailure = 9, - InputOutputBaseTokenMismatch = 10, - ManaOverflow = 11, - InputOutputManaMismatch = 12, - ManaDecayCreationIndexExceedsTargetIndex = 13, - NativeTokenSumUnbalanced = 14, - SimpleTokenSchemeMintedMeltedTokenDecrease = 15, - SimpleTokenSchemeMintingInvalid = 16, - SimpleTokenSchemeMeltingInvalid = 17, - SimpleTokenSchemeMaximumSupplyChanged = 18, - SimpleTokenSchemeGenesisInvalid = 19, - MultiAddressLengthUnlockLengthMismatch = 20, - MultiAddressUnlockThresholdNotReached = 21, - SenderFeatureNotUnlocked = 22, - IssuerFeatureNotUnlocked = 23, - StakingRewardInputMissing = 24, - StakingBlockIssuerFeatureMissing = 25, - StakingCommitmentInputMissing = 26, - StakingRewardClaimingInvalid = 27, - StakingFeatureRemovedBeforeUnbonding = 28, - StakingFeatureModifiedBeforeUnbonding = 29, - StakingStartEpochInvalid = 30, - StakingEndEpochTooEarly = 31, - BlockIssuerCommitmentInputMissing = 32, - BlockIssuanceCreditInputMissing = 33, - BlockIssuerNotExpired = 34, - BlockIssuerExpiryTooEarly = 35, - ManaMovedOffBlockIssuerAccount = 36, - AccountLocked = 37, - TimelockCommitmentInputMissing = 38, - TimelockNotExpired = 39, - ExpirationCommitmentInputMissing = 40, - ExpirationNotUnlockable = 41, - ReturnAmountNotFulFilled = 42, - NewChainOutputHasNonZeroedId = 43, - ChainOutputImmutableFeaturesChanged = 44, - ImplicitAccountDestructionDisallowed = 45, - MultipleImplicitAccountCreationAddresses = 46, - AccountInvalidFoundryCounter = 47, - AnchorInvalidStateTransition = 48, - AnchorInvalidGovernanceTransition = 49, - FoundryTransitionWithoutAccount = 50, - FoundrySerialInvalid = 51, - DelegationCommitmentInputMissing = 52, - DelegationRewardInputMissing = 53, - DelegationRewardsClaimingInvalid = 54, - DelegationOutputTransitionedTwice = 55, - DelegationModified = 56, - DelegationStartEpochInvalid = 57, - DelegationAmountMismatch = 58, - DelegationEndEpochNotZero = 59, - DelegationEndEpochInvalid = 60, - CapabilitiesNativeTokenBurningNotAllowed = 61, - CapabilitiesManaBurningNotAllowed = 62, - CapabilitiesAccountDestructionNotAllowed = 63, - CapabilitiesAnchorDestructionNotAllowed = 64, - CapabilitiesFoundryDestructionNotAllowed = 65, - CapabilitiesNftDestructionNotAllowed = 66, - SemanticValidationFailed = 255, -} - -impl From for iota_sdk::types::block::semantic::TransactionFailureReason { - fn from(value: TransactionFailureReason) -> Self { - match value { - TransactionFailureReason::ConflictRejected => Self::ConflictRejected, - TransactionFailureReason::InputAlreadySpent => Self::InputAlreadySpent, - TransactionFailureReason::InputCreationAfterTxCreation => Self::InputCreationAfterTxCreation, - TransactionFailureReason::UnlockSignatureInvalid => Self::UnlockSignatureInvalid, - TransactionFailureReason::CommitmentInputReferenceInvalid => Self::CommitmentInputReferenceInvalid, - TransactionFailureReason::BicInputReferenceInvalid => Self::BicInputReferenceInvalid, - TransactionFailureReason::RewardInputReferenceInvalid => Self::RewardInputReferenceInvalid, - TransactionFailureReason::StakingRewardCalculationFailure => Self::StakingRewardCalculationFailure, - TransactionFailureReason::DelegationRewardCalculationFailure => Self::DelegationRewardCalculationFailure, - TransactionFailureReason::InputOutputBaseTokenMismatch => Self::InputOutputBaseTokenMismatch, - TransactionFailureReason::ManaOverflow => Self::ManaOverflow, - TransactionFailureReason::InputOutputManaMismatch => Self::InputOutputManaMismatch, - TransactionFailureReason::ManaDecayCreationIndexExceedsTargetIndex => { - Self::ManaDecayCreationIndexExceedsTargetIndex - } - TransactionFailureReason::NativeTokenSumUnbalanced => Self::NativeTokenSumUnbalanced, - TransactionFailureReason::SimpleTokenSchemeMintedMeltedTokenDecrease => { - Self::SimpleTokenSchemeMintedMeltedTokenDecrease - } - TransactionFailureReason::SimpleTokenSchemeMintingInvalid => Self::SimpleTokenSchemeMintingInvalid, - TransactionFailureReason::SimpleTokenSchemeMeltingInvalid => Self::SimpleTokenSchemeMeltingInvalid, - TransactionFailureReason::SimpleTokenSchemeMaximumSupplyChanged => { - Self::SimpleTokenSchemeMaximumSupplyChanged - } - TransactionFailureReason::SimpleTokenSchemeGenesisInvalid => Self::SimpleTokenSchemeGenesisInvalid, - TransactionFailureReason::MultiAddressLengthUnlockLengthMismatch => { - Self::MultiAddressLengthUnlockLengthMismatch - } - TransactionFailureReason::MultiAddressUnlockThresholdNotReached => { - Self::MultiAddressUnlockThresholdNotReached - } - TransactionFailureReason::SenderFeatureNotUnlocked => Self::SenderFeatureNotUnlocked, - TransactionFailureReason::IssuerFeatureNotUnlocked => Self::IssuerFeatureNotUnlocked, - TransactionFailureReason::StakingRewardInputMissing => Self::StakingRewardInputMissing, - TransactionFailureReason::StakingBlockIssuerFeatureMissing => Self::StakingBlockIssuerFeatureMissing, - TransactionFailureReason::StakingCommitmentInputMissing => Self::StakingCommitmentInputMissing, - TransactionFailureReason::StakingRewardClaimingInvalid => Self::StakingRewardClaimingInvalid, - TransactionFailureReason::StakingFeatureRemovedBeforeUnbonding => { - Self::StakingFeatureRemovedBeforeUnbonding - } - TransactionFailureReason::StakingFeatureModifiedBeforeUnbonding => { - Self::StakingFeatureModifiedBeforeUnbonding - } - TransactionFailureReason::StakingStartEpochInvalid => Self::StakingStartEpochInvalid, - TransactionFailureReason::StakingEndEpochTooEarly => Self::StakingEndEpochTooEarly, - TransactionFailureReason::BlockIssuerCommitmentInputMissing => Self::BlockIssuerCommitmentInputMissing, - TransactionFailureReason::BlockIssuanceCreditInputMissing => Self::BlockIssuanceCreditInputMissing, - TransactionFailureReason::BlockIssuerNotExpired => Self::BlockIssuerNotExpired, - TransactionFailureReason::BlockIssuerExpiryTooEarly => Self::BlockIssuerExpiryTooEarly, - TransactionFailureReason::ManaMovedOffBlockIssuerAccount => Self::ManaMovedOffBlockIssuerAccount, - TransactionFailureReason::AccountLocked => Self::AccountLocked, - TransactionFailureReason::TimelockCommitmentInputMissing => Self::TimelockCommitmentInputMissing, - TransactionFailureReason::TimelockNotExpired => Self::TimelockNotExpired, - TransactionFailureReason::ExpirationCommitmentInputMissing => Self::ExpirationCommitmentInputMissing, - TransactionFailureReason::ExpirationNotUnlockable => Self::ExpirationNotUnlockable, - TransactionFailureReason::ReturnAmountNotFulFilled => Self::ReturnAmountNotFulFilled, - TransactionFailureReason::NewChainOutputHasNonZeroedId => Self::NewChainOutputHasNonZeroedId, - TransactionFailureReason::ChainOutputImmutableFeaturesChanged => Self::ChainOutputImmutableFeaturesChanged, - TransactionFailureReason::ImplicitAccountDestructionDisallowed => { - Self::ImplicitAccountDestructionDisallowed - } - TransactionFailureReason::MultipleImplicitAccountCreationAddresses => { - Self::MultipleImplicitAccountCreationAddresses - } - TransactionFailureReason::AccountInvalidFoundryCounter => Self::AccountInvalidFoundryCounter, - TransactionFailureReason::AnchorInvalidStateTransition => Self::AnchorInvalidStateTransition, - TransactionFailureReason::AnchorInvalidGovernanceTransition => Self::AnchorInvalidGovernanceTransition, - TransactionFailureReason::FoundryTransitionWithoutAccount => Self::FoundryTransitionWithoutAccount, - TransactionFailureReason::FoundrySerialInvalid => Self::FoundrySerialInvalid, - TransactionFailureReason::DelegationCommitmentInputMissing => Self::DelegationCommitmentInputMissing, - TransactionFailureReason::DelegationRewardInputMissing => Self::DelegationRewardInputMissing, - TransactionFailureReason::DelegationRewardsClaimingInvalid => Self::DelegationRewardsClaimingInvalid, - TransactionFailureReason::DelegationOutputTransitionedTwice => Self::DelegationOutputTransitionedTwice, - TransactionFailureReason::DelegationModified => Self::DelegationModified, - TransactionFailureReason::DelegationStartEpochInvalid => Self::DelegationStartEpochInvalid, - TransactionFailureReason::DelegationAmountMismatch => Self::DelegationAmountMismatch, - TransactionFailureReason::DelegationEndEpochNotZero => Self::DelegationEndEpochNotZero, - TransactionFailureReason::DelegationEndEpochInvalid => Self::DelegationEndEpochInvalid, - TransactionFailureReason::CapabilitiesNativeTokenBurningNotAllowed => { - Self::CapabilitiesNativeTokenBurningNotAllowed - } - TransactionFailureReason::CapabilitiesManaBurningNotAllowed => Self::CapabilitiesManaBurningNotAllowed, - TransactionFailureReason::CapabilitiesAccountDestructionNotAllowed => { - Self::CapabilitiesAccountDestructionNotAllowed - } - TransactionFailureReason::CapabilitiesAnchorDestructionNotAllowed => { - Self::CapabilitiesAnchorDestructionNotAllowed - } - TransactionFailureReason::CapabilitiesFoundryDestructionNotAllowed => { - Self::CapabilitiesFoundryDestructionNotAllowed - } - TransactionFailureReason::CapabilitiesNftDestructionNotAllowed => { - Self::CapabilitiesNftDestructionNotAllowed - } - TransactionFailureReason::SemanticValidationFailed => Self::SemanticValidationFailed, - } - } -} diff --git a/src/model/ledger.rs b/src/model/ledger.rs index 33095bba1..af2a0643e 100644 --- a/src/model/ledger.rs +++ b/src/model/ledger.rs @@ -9,6 +9,7 @@ use iota_sdk::types::block::{ address::Address, output::{Output, OutputId}, payload::signed_transaction::TransactionId, + protocol::ProtocolParameters, slot::{SlotCommitmentId, SlotIndex}, BlockId, }; @@ -41,11 +42,40 @@ impl LedgerOutput { self.output().amount() } - pub fn address(&self) -> Option<&Address> { + pub fn mana(&self) -> u64 { + self.output().mana() + } + + pub fn owning_address(&self) -> Address { + match self.output() { + Output::Basic(output) => output.address().clone(), + Output::Account(output) => output.address().clone(), + Output::Anchor(output) => output.state_controller_address().clone(), + Output::Foundry(output) => Address::from(*output.account_address()), + Output::Nft(output) => output.address().clone(), + Output::Delegation(output) => output.address().clone(), + } + } + + /// Returns the [`Address`] that is in control of the output at the given slot. + pub fn locked_address_at(&self, slot: impl Into, protocol_parameters: &ProtocolParameters) -> Address { + let owning_address = self.owning_address(); self.output() .unlock_conditions() - .and_then(|uc| uc.address()) - .map(|uc| uc.address()) + .unwrap() + .locked_address( + &owning_address, + slot.into(), + protocol_parameters.committable_age_range(), + ) + .unwrap() + .cloned() + .unwrap_or(owning_address) + } + + /// Returns the [`Address`] that is in control of the output at the spent slot. + pub fn locked_address(&self, protocol_parameters: &ProtocolParameters) -> Address { + self.locked_address_at(self.slot_booked, protocol_parameters) } pub fn kind(&self) -> &str { @@ -84,8 +114,22 @@ impl LedgerSpent { self.output().amount() } - pub fn address(&self) -> Option<&Address> { - self.output.address() + pub fn slot_booked(&self) -> SlotIndex { + self.output.slot_booked + } + + pub fn owning_address(&self) -> Address { + self.output.owning_address() + } + + /// Returns the [`Address`] that is in control of the output at the given slot. + pub fn locked_address_at(&self, slot: impl Into, protocol_parameters: &ProtocolParameters) -> Address { + self.output.locked_address_at(slot, protocol_parameters) + } + + /// Returns the [`Address`] that is in control of the output at the booked slot. + pub fn locked_address(&self, protocol_parameters: &ProtocolParameters) -> Address { + self.locked_address_at(self.slot_spent, protocol_parameters) } }