diff --git a/Cargo.lock b/Cargo.lock index 3c8943d..9bc95c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -87,9 +87,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.13" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e614738943d3f68c628ae3dbce7c3daffb196665f82f8c8ea6b65de73c79429" +checksum = "e26a9844c659a2a293d239c7910b752f8487fe122c6c8bd1659bf85a6507c302" dependencies = [ "flate2", "futures-core", @@ -238,6 +238,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bech32" version = "0.9.1" @@ -271,6 +277,15 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "block-buffer" version = "0.9.0" @@ -280,6 +295,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "blocking" version = "1.6.1" @@ -322,9 +346,9 @@ checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "cc" -version = "1.1.28" +version = "1.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1" +checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" dependencies = [ "jobserver", "libc", @@ -389,7 +413,7 @@ dependencies = [ [[package]] name = "cncli" -version = "6.4.1" +version = "6.5.0" dependencies = [ "async-std", "bech32 0.11.0", @@ -437,6 +461,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -501,6 +531,16 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "cryptoxide" version = "0.4.4" @@ -514,7 +554,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" dependencies = [ "byteorder", - "digest", + "digest 0.9.0", "rand_core 0.5.1", "subtle", "zeroize", @@ -526,12 +566,49 @@ version = "3.2.0" source = "git+https://github.com/txpipe/curve25519-dalek?branch=ietf03_vrf_compat_ell2#70a36f41cfc3fbb7357ec3062201b911787decba" dependencies = [ "byteorder", - "digest", + "digest 0.9.0", "rand_core 0.5.1", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "digest" version = "0.9.0" @@ -541,6 +618,41 @@ dependencies = [ "generic-array", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", + "subtle", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek 4.1.3", + "ed25519", + "serde", + "sha2 0.10.8", + "subtle", + "zeroize", +] + [[package]] name = "either" version = "1.13.0" @@ -602,6 +714,12 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "flate2" version = "1.0.34" @@ -1022,13 +1140,25 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kes-summed-ed25519" +version = "0.2.1" +source = "git+https://github.com/txpipe/kes?rev=f69fb357d46f6a18925543d785850059569d7e78#f69fb357d46f6a18925543d785850059569d7e78" +dependencies = [ + "blake2", + "ed25519-dalek", + "rand_core 0.6.4", + "thiserror", + "zeroize", +] + [[package]] name = "kv-log-macro" version = "1.0.7" @@ -1274,7 +1404,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pallas-addresses" version = "0.30.2" -source = "git+https://github.com/txpipe/pallas?rev=de88df1986dc1487452075dd29cec0996a46e3c3#de88df1986dc1487452075dd29cec0996a46e3c3" +source = "git+https://github.com/txpipe/pallas?rev=7f988a16d412d4891408f99785372a4ef617984d#7f988a16d412d4891408f99785372a4ef617984d" dependencies = [ "base58", "bech32 0.9.1", @@ -1289,7 +1419,7 @@ dependencies = [ [[package]] name = "pallas-codec" version = "0.30.2" -source = "git+https://github.com/txpipe/pallas?rev=de88df1986dc1487452075dd29cec0996a46e3c3#de88df1986dc1487452075dd29cec0996a46e3c3" +source = "git+https://github.com/txpipe/pallas?rev=7f988a16d412d4891408f99785372a4ef617984d#7f988a16d412d4891408f99785372a4ef617984d" dependencies = [ "hex", "minicbor 0.20.0", @@ -1300,21 +1430,23 @@ dependencies = [ [[package]] name = "pallas-crypto" version = "0.30.2" -source = "git+https://github.com/txpipe/pallas?rev=de88df1986dc1487452075dd29cec0996a46e3c3#de88df1986dc1487452075dd29cec0996a46e3c3" +source = "git+https://github.com/txpipe/pallas?rev=7f988a16d412d4891408f99785372a4ef617984d#7f988a16d412d4891408f99785372a4ef617984d" dependencies = [ "cryptoxide", "hex", + "kes-summed-ed25519", "pallas-codec", "rand_core 0.6.4", "serde", "thiserror", "vrf_dalek", + "zeroize", ] [[package]] name = "pallas-math" version = "0.30.2" -source = "git+https://github.com/txpipe/pallas?rev=de88df1986dc1487452075dd29cec0996a46e3c3#de88df1986dc1487452075dd29cec0996a46e3c3" +source = "git+https://github.com/txpipe/pallas?rev=7f988a16d412d4891408f99785372a4ef617984d#7f988a16d412d4891408f99785372a4ef617984d" dependencies = [ "malachite", "malachite-base", @@ -1326,7 +1458,7 @@ dependencies = [ [[package]] name = "pallas-network" version = "0.30.2" -source = "git+https://github.com/txpipe/pallas?rev=de88df1986dc1487452075dd29cec0996a46e3c3#de88df1986dc1487452075dd29cec0996a46e3c3" +source = "git+https://github.com/txpipe/pallas?rev=7f988a16d412d4891408f99785372a4ef617984d#7f988a16d412d4891408f99785372a4ef617984d" dependencies = [ "byteorder", "hex", @@ -1343,7 +1475,7 @@ dependencies = [ [[package]] name = "pallas-primitives" version = "0.30.2" -source = "git+https://github.com/txpipe/pallas?rev=de88df1986dc1487452075dd29cec0996a46e3c3#de88df1986dc1487452075dd29cec0996a46e3c3" +source = "git+https://github.com/txpipe/pallas?rev=7f988a16d412d4891408f99785372a4ef617984d#7f988a16d412d4891408f99785372a4ef617984d" dependencies = [ "base58", "bech32 0.9.1", @@ -1358,7 +1490,7 @@ dependencies = [ [[package]] name = "pallas-traverse" version = "0.30.2" -source = "git+https://github.com/txpipe/pallas?rev=de88df1986dc1487452075dd29cec0996a46e3c3#de88df1986dc1487452075dd29cec0996a46e3c3" +source = "git+https://github.com/txpipe/pallas?rev=7f988a16d412d4891408f99785372a4ef617984d#7f988a16d412d4891408f99785372a4ef617984d" dependencies = [ "hex", "itertools 0.13.0", @@ -1459,6 +1591,16 @@ dependencies = [ "futures-io", ] +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.31" @@ -1515,9 +1657,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] @@ -1640,9 +1782,9 @@ dependencies = [ [[package]] name = "redb" -version = "2.1.3" +version = "2.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4760ad04a88ef77075ba86ba9ea79b919e6bab29c1764c5747237cd6eaedcaa" +checksum = "074373f3e7e5d27d8741d19512232adb47be8622d3daef3a45bcae72050c3d2a" dependencies = [ "libc", ] @@ -1762,6 +1904,15 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.37" @@ -1821,6 +1972,12 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "serde" version = "1.0.210" @@ -1892,13 +2049,24 @@ version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ - "block-buffer", + "block-buffer 0.9.0", "cfg-if", "cpufeatures", - "digest", + "digest 0.9.0", "opaque-debug", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -1914,6 +2082,15 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "siphasher" version = "0.3.11" @@ -1951,6 +2128,16 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "strsim" version = "0.8.0" @@ -2295,7 +2482,7 @@ dependencies = [ "curve25519-dalek 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "curve25519-dalek 3.2.0 (git+https://github.com/txpipe/curve25519-dalek?branch=ietf03_vrf_compat_ell2)", "rand_core 0.5.1", - "sha2", + "sha2 0.9.9", "thiserror", ] @@ -2322,9 +2509,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -2333,9 +2520,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", @@ -2348,9 +2535,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -2360,9 +2547,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2370,9 +2557,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", @@ -2383,15 +2570,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 2c64e9e..cd22c2a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cncli" -version = "6.4.1" +version = "6.5.0" authors = ["Andrew Westberg "] edition = "2021" build = "build.rs" @@ -12,10 +12,10 @@ async-std = "1.13" bech32 = "0.11" bincode = "1.3.3" byteorder = "1.5" -pallas-crypto = { git = "https://github.com/txpipe/pallas", rev = "de88df1986dc1487452075dd29cec0996a46e3c3" } -pallas-math = { git = "https://github.com/txpipe/pallas", rev = "de88df1986dc1487452075dd29cec0996a46e3c3" } -pallas-network = { git = "https://github.com/txpipe/pallas", rev = "de88df1986dc1487452075dd29cec0996a46e3c3" } -pallas-traverse = { git = "https://github.com/txpipe/pallas", rev = "de88df1986dc1487452075dd29cec0996a46e3c3" } +pallas-crypto = { git = "https://github.com/txpipe/pallas", rev = "7f988a16d412d4891408f99785372a4ef617984d" } +pallas-math = { git = "https://github.com/txpipe/pallas", rev = "7f988a16d412d4891408f99785372a4ef617984d" } +pallas-network = { git = "https://github.com/txpipe/pallas", rev = "7f988a16d412d4891408f99785372a4ef617984d" } +pallas-traverse = { git = "https://github.com/txpipe/pallas", rev = "7f988a16d412d4891408f99785372a4ef617984d" } #pallas-crypto = "0.30" #pallas-math = "0.30" #pallas-network = "0.30" diff --git a/USAGE.md b/USAGE.md index 269cfd8..fb62300 100644 --- a/USAGE.md +++ b/USAGE.md @@ -665,4 +665,28 @@ OPTIONS: --socket-path cardano-node socket path --stake-prefix The prefix for stake addresses, (stake for mainnet, stake_test for testnet) [default: stake] +``` + +### Pool-Stake Command + +This command retrieves the pool stake distribution snapshot for the current epoch. The snapshot is saved to a CSV file. Each epoch has three snapshots: mark, set, and go. The mark snapshot is taken at the beginning of the epoch, the set snapshot is one epoch ago, and the go snapshot is two epochs ago. + +#### Retrieve the Pool Stake Distribution Snapshot +```bash +$ cncli pool-stake --help +cncli-pool-stake 6.5.0 + +USAGE: + cncli pool-stake [OPTIONS] --socket-path + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + --name PoolStake snapshot name to retrieve (mark, set, go) [default: mark] + --network-id The network identifier, (1 for mainnet, 0 for testnet) [default: 1] + --network-magic network magic. [default: 764824073] + --output-file The name of the output file (CSV format) [default: mark.csv] + --socket-path cardano-node socket path ``` \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index c239605..965f9ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -300,6 +300,26 @@ pub enum Command { #[structopt(long, default_value = "mark.csv", help = "The name of the output file (CSV format)")] output_file: String, }, + PoolStake { + #[structopt(parse(from_os_str), long, help = "cardano-node socket path")] + socket_path: PathBuf, + #[structopt(long, default_value = "764824073", help = "network magic.")] + network_magic: u64, + #[structopt( + long, + default_value = "mark", + help = "PoolStake snapshot name to retrieve (mark, set, go)" + )] + name: String, + #[structopt( + long, + default_value = "1", + help = "The network identifier, (1 for mainnet, 0 for testnet)" + )] + network_id: u8, + #[structopt(long, default_value = "mark.csv", help = "The name of the output file (CSV format)")] + output_file: String, + }, } pub async fn start(cmd: Command) { @@ -512,5 +532,24 @@ pub async fn start(cmd: Command) { handle_error(error); } } + Command::PoolStake { + ref socket_path, + ref network_magic, + ref name, + ref network_id, + ref output_file, + } => { + if let Err(error) = snapshot::pool_stake_dump( + socket_path, + *network_magic, + name.as_str(), + *network_id, + output_file.as_str(), + ) + .await + { + handle_error(error); + } + } } } diff --git a/src/nodeclient/snapshot/mod.rs b/src/nodeclient/snapshot/mod.rs index b1fa830..9e0c6d9 100644 --- a/src/nodeclient/snapshot/mod.rs +++ b/src/nodeclient/snapshot/mod.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::io::Write; use std::path::PathBuf; @@ -91,7 +92,8 @@ pub(crate) async fn dump( decoder.skip()?; // skip the 0th element decoder.skip()?; // skip the 1st element decoder.skip()?; // skip the 2nd element - // array element [3] + + // array element [3] let snapshots_array_len = decoder .array()? .ok_or(Error::UnexpectedArrayLength { expected: 4, actual: 0 })?; @@ -166,6 +168,7 @@ pub(crate) async fn dump( writeln!(output_file, "{},{},", stake_address, lovelace)?; } Type::Break => { + decoder.skip()?; break; } _ => { @@ -179,6 +182,191 @@ pub(crate) async fn dump( Ok(()) } +pub(crate) async fn pool_stake_dump( + socket_path: &PathBuf, + network_magic: u64, + name: &str, + network_id: u8, + output_file: &str, +) -> Result<(), Error> { + let mut client = NodeClient::connect(socket_path, network_magic).await.unwrap(); + + // convert name into a Snapshot enum + let snapshot = match name { + "mark" => Snapshot::Mark, + "set" => Snapshot::Set, + "go" => Snapshot::Go, + _ => return Err(Error::Snapshot(format!("Unknown snapshot name: {}", name))), + }; + + let client = client.statequery(); + + client.acquire(None).await?; + + let era = queries_v16::get_current_era(client).await?; + debug!("Current era: {}", era); + + let cbor = queries_v16::get_cbor(client, era, BlockQuery::DebugNewEpochState).await?; + client.send_release().await?; + + // Save the CBOR to a file + let cbor_bytes = &cbor[0].0; + // let output_file = std::fs::File::create(output_file)?; + // let mut output_file = std::io::BufWriter::new(output_file); + // output_file.write_all(cbor_bytes)?; + + let mut decoder = minicbor::Decoder::new(cbor_bytes); + // top level is an array + let stake_array_len = decoder + .array()? + .ok_or(Error::UnexpectedArrayLength { expected: 7, actual: 0 })?; + if stake_array_len != 7 { + return Err(Error::UnexpectedArrayLength { + expected: 7, + actual: stake_array_len, + }); + } + decoder.skip()?; // skip the 0th element + decoder.skip()?; // skip the 1st element + decoder.skip()?; // skip the 2nd element + // array element [3] + let snapshots_array_len = decoder + .array()? + .ok_or(Error::UnexpectedArrayLength { expected: 4, actual: 0 })?; + if snapshots_array_len != 4 { + return Err(Error::UnexpectedArrayLength { + expected: 4, + actual: snapshots_array_len, + }); + } + decoder.skip()?; // skip the 0th element + decoder.skip()?; // skip the 1st element + // array element [3][2] + let inner_array_len = decoder + .array()? + .ok_or(Error::UnexpectedArrayLength { expected: 4, actual: 0 })?; + if inner_array_len != 4 { + return Err(Error::UnexpectedArrayLength { + expected: 4, + actual: inner_array_len, + }); + } + + match snapshot { + Snapshot::Mark => { + // mark snapshot is at index 0 so no skips needed + } + Snapshot::Set => { + // set snapshot is at index 1 so skip the mark snapshot + decoder.skip()?; + } + Snapshot::Go => { + // go snapshot is at index 2 so skip the mark and set snapshots + decoder.skip()?; + decoder.skip()?; + } + } + + // array element [3][2][snapshot] + let snapshot_array_len = decoder + .array()? + .ok_or(Error::UnexpectedArrayLength { expected: 3, actual: 0 })?; + if snapshot_array_len != 3 { + return Err(Error::UnexpectedArrayLength { + expected: 3, + actual: snapshot_array_len, + }); + } + + let output_file = std::fs::File::create(output_file)?; + let mut output_file = std::io::BufWriter::new(output_file); + + let mut stake_address_to_amount_map: HashMap, u64> = HashMap::new(); + let mut stake_address_to_pool_map: HashMap, Vec> = HashMap::new(); + + // loop through each map item + // array element [3][2][snapshot][0] is an indeterminate-length map + decoder.map()?; + loop { + let datatype = decoder.datatype()?; + match datatype { + Type::Array => { + decoder.array()?; + let address_type = decoder.u8()?; // the type of stake address + let stake_key_prefix = [match address_type { + 0 => 0xe0u8, // key-based stake address + 1 => 0xf0u8, // script-based stake address + _ => return Err(Error::Snapshot(format!("Unknown address type: {}", address_type))), + } | network_id]; + let stake_key_bytes = decoder.bytes()?; + let stake_key_bytes = [&stake_key_prefix, stake_key_bytes].concat(); + let lovelace = decoder.u64()?; + stake_address_to_amount_map.insert(stake_key_bytes, lovelace); + // writeln!(output_file, "{},{},", hex::encode(stake_key_bytes), lovelace)?; + } + Type::Break => { + decoder.skip()?; + break; + } + _ => { + return Err(UnexpectedCborType { value: datatype }); + } + } + } + // array element [3][2][snapshot][1] is an indeterminate-length map + decoder.map()?; + loop { + let datatype = decoder.datatype()?; + match datatype { + Type::Array => { + decoder.array()?; + let address_type = decoder.u8()?; // the type of stake address + let stake_key_prefix = [match address_type { + 0 => 0xe0u8, // key-based stake address + 1 => 0xf0u8, // script-based stake address + _ => return Err(Error::Snapshot(format!("Unknown address type: {}", address_type))), + } | network_id]; + let stake_key_bytes = decoder.bytes()?; + let stake_key_bytes = [&stake_key_prefix, stake_key_bytes].concat(); + let pool_id = decoder.bytes()?; + stake_address_to_pool_map.insert(stake_key_bytes, pool_id.to_vec()); + } + Type::Break => { + decoder.skip()?; + break; + } + _ => { + return Err(UnexpectedCborType { value: datatype }); + } + } + } + + let pool_id_to_total_stake_map: HashMap, u64> = + stake_address_to_pool_map + .iter() + .fold(HashMap::new(), |mut acc, (stake_key_bytes, pool_id)| { + let lovelace = stake_address_to_amount_map.get(stake_key_bytes).unwrap(); + let total_stake = acc.entry(pool_id.to_vec()).or_insert(0); + *total_stake += lovelace; + acc + }); + + let total_stake = pool_id_to_total_stake_map + .iter() + .fold(0, |acc, (_, total_stake)| acc + total_stake); + + let mut pool_id_to_total_stake_vec: Vec<(&Vec, &u64)> = pool_id_to_total_stake_map.iter().collect(); + pool_id_to_total_stake_vec.sort_by(|a, b| b.1.cmp(a.1)); // Sort in descending order by stake + + pool_id_to_total_stake_vec.iter().for_each(|(pool_id, pool_stake)| { + writeln!(output_file, "{},{},{},", hex::encode(pool_id), pool_stake, total_stake).unwrap(); + }); + + output_file.flush()?; + + Ok(()) +} + fn encode_bech32(addr: &[u8], hrp: Hrp) -> Result { let encoded = bech32::encode::(hrp, addr)?; Ok(encoded)