diff --git a/Cargo.lock b/Cargo.lock index 18730275..40e84650 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,7 +30,7 @@ dependencies = [ "rayon", "serde", "serde_json", - "serde_with 3.14.1", + "serde_with 3.15.0", "tokio", "tracing", ] @@ -49,7 +49,7 @@ dependencies = [ "imbl", "serde", "serde_json", - "serde_with 3.14.1", + "serde_with 3.15.0", "tokio", "tracing", ] @@ -109,7 +109,7 @@ dependencies = [ "hex", "serde", "serde_json", - "serde_with 3.14.1", + "serde_with 3.15.0", "tokio", "tracing", ] @@ -160,7 +160,7 @@ dependencies = [ "hex", "serde", "serde_json", - "serde_with 3.14.1", + "serde_with 3.15.0", "tokio", "tracing", ] @@ -200,7 +200,7 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", - "serde_with 3.14.1", + "serde_with 3.15.0", "tokio", "tracing", ] @@ -224,7 +224,7 @@ dependencies = [ "serde", "serde_cbor", "serde_json", - "serde_with 3.14.1", + "serde_with 3.15.0", "tokio", "tracing", ] @@ -275,7 +275,7 @@ dependencies = [ "rayon", "serde", "serde_json", - "serde_with 3.14.1", + "serde_with 3.15.0", "tokio", "tracing", ] @@ -295,7 +295,7 @@ dependencies = [ "serde", "serde_json", "serde_json_any_key", - "serde_with 3.14.1", + "serde_with 3.15.0", "tokio", "tracing", ] @@ -425,7 +425,7 @@ dependencies = [ "config", "serde", "serde_json", - "serde_with 3.14.1", + "serde_with 3.15.0", "tokio", "tracing", "tracing-subscriber", @@ -467,9 +467,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] @@ -591,9 +591,9 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "archery" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae2ed21cd55021f05707a807a5fc85695dafb98832921f6cfa06db67ca5b869" +checksum = "70e0a5f99dfebb87bb342d0f53bb92c81842e100bbb915223e38349580e5441d" [[package]] name = "arraydeque" @@ -619,7 +619,7 @@ dependencies = [ "nom 7.1.3", "num-traits", "rusticata-macros", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", ] @@ -660,9 +660,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.30" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "977eb15ea9efd848bb8a4a1a2500347ed7f0bf794edf0dc3ddcf439f43d36b23" +checksum = "5a89bce6054c720275ac2432fbba080a66a2106a44a1b804553930ca6909f4e0" dependencies = [ "compression-codecs", "compression-core", @@ -745,7 +745,7 @@ dependencies = [ "polling 3.11.0", "rustix 1.1.2", "slab", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -877,9 +877,9 @@ checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" [[package]] name = "backtrace" -version = "0.3.75" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", "cfg-if", @@ -887,7 +887,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] [[package]] @@ -1192,9 +1192,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.23.2" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" [[package]] name = "byteorder" @@ -1330,9 +1330,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.38" +version = "1.2.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" +checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" dependencies = [ "find-msvc-tools", "jobserver", @@ -1363,7 +1363,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -1432,9 +1432,9 @@ checksum = "ea0095f6103c2a8b44acd6fd15960c801dafebf02e21940360833e0673f48ba7" [[package]] name = "compression-codecs" -version = "0.4.30" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "485abf41ac0c8047c07c87c72c8fb3eb5197f6e9d7ded615dfd1a00ae00a0f64" +checksum = "ef8a506ec4b81c460798f572caead636d57d3d7e940f998160f52bd254bf2d23" dependencies = [ "brotli", "compression-core", @@ -1461,9 +1461,9 @@ dependencies = [ [[package]] name = "config" -version = "0.15.16" +version = "0.15.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef036f0ecf99baef11555578630e2cca559909b4c50822dbba828c252d21c49" +checksum = "180e549344080374f9b32ed41bf3b6b57885ff6a289367b3dbc10eea8acc1918" dependencies = [ "async-trait", "convert_case", @@ -1775,7 +1775,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.11", + "parking_lot_core 0.9.12", ] [[package]] @@ -1824,12 +1824,12 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" dependencies = [ "powerfmt", - "serde", + "serde_core", ] [[package]] @@ -1985,7 +1985,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -2059,9 +2059,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" +checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" [[package]] name = "fixed" @@ -2106,9 +2106,9 @@ checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe" [[package]] name = "flate2" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" dependencies = [ "crc32fast", "miniz_oxide", @@ -2372,9 +2372,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "glob" @@ -3024,9 +3024,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.80" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" dependencies = [ "once_cell", "wasm-bindgen", @@ -3071,7 +3071,7 @@ dependencies = [ "flume", "futures-core", "futures-io", - "parking_lot 0.12.4", + "parking_lot 0.12.5", "pinky-swear", "reactor-trait", "serde", @@ -3096,9 +3096,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.175" +version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] name = "libm" @@ -3114,7 +3114,7 @@ checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ "bitflags 2.9.4", "libc", - "redox_syscall 0.5.17", + "redox_syscall 0.5.18", ] [[package]] @@ -3147,11 +3147,10 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] @@ -3182,9 +3181,9 @@ checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] name = "lsm-tree" -version = "2.10.3" +version = "2.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab73c02eadb3dc12c0024e5b61d6284e6d59064e67e74fbad77856caa56f62c7" +checksum = "799399117a2bfb37660e08be33f470958babb98386b04185288d829df362ea15" dependencies = [ "byteorder", "crossbeam-skiplist", @@ -3206,9 +3205,9 @@ dependencies = [ [[package]] name = "lz4_flex" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5" +checksum = "08ab2867e3eeeca90e844d1940eab391c9dc5228783db2ed999acbc0a9ed375a" [[package]] name = "matchers" @@ -3227,9 +3226,9 @@ checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "mime" @@ -3292,6 +3291,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -3331,7 +3331,7 @@ dependencies = [ "serde_json", "sha2", "slog", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "walkdir", ] @@ -3359,7 +3359,7 @@ dependencies = [ "slog", "strum", "tar", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "uuid", "zstd", @@ -3394,11 +3394,11 @@ dependencies = [ "serde", "serde_bytes", "serde_json", - "serde_with 3.14.1", + "serde_with 3.15.0", "sha2", "slog", "strum", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "typetag", "walkdir", @@ -3421,7 +3421,7 @@ dependencies = [ "rayon", "rug", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -3576,9 +3576,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.7" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] @@ -3658,7 +3658,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", ] @@ -3688,7 +3688,7 @@ dependencies = [ "opentelemetry_sdk", "prost", "reqwest 0.12.23", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tonic 0.13.1", "tracing", @@ -3730,7 +3730,7 @@ dependencies = [ "percent-encoding", "rand 0.9.2", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-stream", ] @@ -3763,7 +3763,7 @@ dependencies = [ "rc2", "sha1", "sha2", - "thiserror 2.0.16", + "thiserror 2.0.17", "x509-parser", ] @@ -3844,7 +3844,7 @@ dependencies = [ "pallas-primitives", "serde", "serde_json", - "serde_with 3.14.1", + "serde_with 3.15.0", ] [[package]] @@ -3994,12 +3994,12 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", - "parking_lot_core 0.9.11", + "parking_lot_core 0.9.12", ] [[package]] @@ -4018,15 +4018,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.17", + "redox_syscall 0.5.18", "smallvec", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] [[package]] @@ -4123,20 +4123,19 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e0a3a33733faeaf8651dfee72dd0f388f0c8e5ad496a3478fa5a922f49cfa8" +checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4" dependencies = [ "memchr", - "thiserror 2.0.16", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc58706f770acb1dbd0973e6530a3cff4746fb721207feb3a8a6064cd0b6c663" +checksum = "187da9a3030dbafabbbfb20cb323b976dc7b7ce91fcd84f2f74d6e31d378e2de" dependencies = [ "pest", "pest_generator", @@ -4144,9 +4143,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d4f36811dfe07f7b8573462465d5cb8965fffc2e71ae377a33aecf14c2c9a2f" +checksum = "49b401d98f5757ebe97a26085998d6c0eecec4995cad6ab7fc30ffdf4b052843" dependencies = [ "pest", "pest_meta", @@ -4157,9 +4156,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42919b05089acbd0a5dcd5405fb304d17d1053847b81163d09c4ad18ce8e8420" +checksum = "72f27a2cfee9f9039c4d86faa5af122a0ac3851441a34865b8a043b46be0065a" dependencies = [ "pest", "sha2", @@ -4215,7 +4214,7 @@ checksum = "b1ea6e230dd3a64d61bcb8b79e597d3ab6b4c94ec7a234ce687dd718b4f2e657" dependencies = [ "doc-comment", "flume", - "parking_lot 0.12.4", + "parking_lot 0.12.5", "tracing", ] @@ -4303,7 +4302,7 @@ dependencies = [ "hermit-abi 0.5.2", "pin-project-lite", "rustix 1.1.2", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -4432,12 +4431,12 @@ dependencies = [ [[package]] name = "quick_cache" -version = "0.6.16" +version = "0.6.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ad6644cb07b7f3488b9f3d2fde3b4c0a7fa367cafefb39dff93a659f76eb786" +checksum = "ba15f5bccfb18c666351668b97bbff66da5093f96757ca15299e4e594fe1316e" dependencies = [ "equivalent", - "hashbrown 0.15.5", + "hashbrown 0.16.0", ] [[package]] @@ -4454,7 +4453,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2 0.6.0", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tracing", "web-time", @@ -4475,7 +4474,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.16", + "thiserror 2.0.17", "tinyvec", "tracing", "web-time", @@ -4497,9 +4496,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] @@ -4641,27 +4640,27 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.17" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags 2.9.4", ] [[package]] name = "ref-cast" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", @@ -4670,9 +4669,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.2" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" dependencies = [ "aho-corasick", "memchr", @@ -4682,9 +4681,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" dependencies = [ "aho-corasick", "memchr", @@ -4942,7 +4941,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.11.0", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -5016,9 +5015,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.6" +version = "0.103.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8572f3c2cb9934231157b45499fc41e1f58c589fdfb81a844ba873265e80f8eb" +checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" dependencies = [ "ring", "rustls-pki-types", @@ -5061,7 +5060,7 @@ version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -5154,9 +5153,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -5196,18 +5195,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -5287,9 +5286,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.14.1" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c522100790450cf78eeac1507263d0a350d4d5b30df0c8e1fe051a10c22b376e" +checksum = "6093cd8c01b25262b84927e0f7151692158fab02d961e04c979d3903eba7ecc5" dependencies = [ "base64 0.22.1", "chrono", @@ -5298,10 +5297,9 @@ dependencies = [ "indexmap 2.11.4", "schemars 0.9.0", "schemars 1.0.4", - "serde", - "serde_derive", + "serde_core", "serde_json", - "serde_with_macros 3.14.1", + "serde_with_macros 3.15.0", "time", ] @@ -5319,9 +5317,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.14.1" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327ada00f7d64abaac1e55a6911e90cf665aa051b9a561c7006c157f4633135e" +checksum = "a7e6c180db0816026a61afa1cff5344fb7ebded7e4d3062772179f2501481c27" dependencies = [ "darling 0.21.3", "proc-macro2", @@ -5399,6 +5397,12 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "simdutf8" version = "0.1.5" @@ -5429,9 +5433,15 @@ dependencies = [ [[package]] name = "slog" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" +checksum = "713701148774f80b669126b7f7becffcab60d78bfc5ff1e18c02baabbf8b1ff9" +dependencies = [ + "anyhow", + "erased-serde", + "rustversion", + "serde_core", +] [[package]] name = "smallvec" @@ -5654,15 +5664,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.22.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand 2.3.0", "getrandom 0.3.3", "once_cell", "rustix 1.1.2", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -5676,11 +5686,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.17", ] [[package]] @@ -5696,9 +5706,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -5819,7 +5829,7 @@ dependencies = [ "io-uring", "libc", "mio", - "parking_lot 0.12.4", + "parking_lot 0.12.5", "pin-project-lite", "signal-hook-registry", "slab", @@ -5862,9 +5872,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f63835928ca123f1bef57abbcd23bb2ba0ac9ae1235f1e65bda0d06e7786bd" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", "tokio", @@ -6144,15 +6154,15 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "typetag" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f22b40dd7bfe8c14230cf9702081366421890435b2d625fa92b4acc4c3de6f" +checksum = "be2212c8a9b9bcfca32024de14998494cf9a5dfa59ea1b829de98bac374b86bf" dependencies = [ "erased-serde", "inventory", @@ -6163,9 +6173,9 @@ dependencies = [ [[package]] name = "typetag-impl" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35f5380909ffc31b4de4f4bdf96b877175a016aa2ca98cee39fcfd8c4d53d952" +checksum = "27a7a9b72ba121f6f1f6c3632b85604cac41aedb5ddc70accbebb6cac83de846" dependencies = [ "proc-macro2", "quote", @@ -6354,9 +6364,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.103" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" dependencies = [ "cfg-if", "once_cell", @@ -6367,9 +6377,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.103" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" dependencies = [ "bumpalo", "log", @@ -6381,9 +6391,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.53" +version = "0.4.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0b221ff421256839509adbb55998214a70d829d3a28c69b4a6672e9d2a42f67" +checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" dependencies = [ "cfg-if", "js-sys", @@ -6394,9 +6404,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.103" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6404,9 +6414,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.103" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", @@ -6417,9 +6427,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.103" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" dependencies = [ "unicode-ident", ] @@ -6439,9 +6449,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.80" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" dependencies = [ "js-sys", "wasm-bindgen", @@ -6488,7 +6498,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -6508,22 +6518,22 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.62.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.2.0", - "windows-result 0.4.0", - "windows-strings 0.5.0", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", ] [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", @@ -6532,9 +6542,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", @@ -6549,9 +6559,9 @@ checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-link" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-registry" @@ -6575,11 +6585,11 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -6593,11 +6603,11 @@ dependencies = [ [[package]] name = "windows-strings" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -6633,16 +6643,16 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.3", + "windows-targets 0.53.5", ] [[package]] name = "windows-sys" -version = "0.61.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -6678,19 +6688,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.3" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.1.3", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -6707,9 +6717,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -6725,9 +6735,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -6743,9 +6753,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -6755,9 +6765,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -6773,9 +6783,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -6791,9 +6801,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -6809,9 +6819,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -6827,9 +6837,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" @@ -6895,7 +6905,7 @@ dependencies = [ "nom 7.1.3", "oid-registry", "rusticata-macros", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", ] @@ -6993,9 +7003,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] diff --git a/common/src/protocol_params.rs b/common/src/protocol_params.rs index b3339ec0..ffb1f0b1 100644 --- a/common/src/protocol_params.rs +++ b/common/src/protocol_params.rs @@ -4,7 +4,7 @@ use crate::{ BlockVersionData, Committee, Constitution, CostModel, DRepVotingThresholds, Era, ExUnitPrices, ExUnits, NetworkId, PoolVotingThresholds, ProtocolConsts, }; -use anyhow::Result; +use anyhow::{bail, Result}; use blake2::{digest::consts::U32, Blake2b, Digest}; use chrono::{DateTime, Utc}; use serde_with::serde_as; @@ -220,11 +220,27 @@ pub struct ConwayParams { pub committee: Committee, } -#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct ProtocolVersion { - pub minor: u64, pub major: u64, + pub minor: u64, +} + +impl ProtocolVersion { + pub fn new(major: u64, minor: u64) -> Self { + Self { major, minor } + } + + pub fn is_chang(&self) -> Result { + if self.major == 9 { + if self.minor != 0 { + bail!("Chang version 9.xx with nonzero xx is not supported") + } + return Ok(true); + } + Ok(false) + } } #[derive( @@ -356,3 +372,43 @@ impl Nonces { slot + window < next_epoch_first_slot } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_protocol_version_order() { + let v9_0 = ProtocolVersion::new(9, 0); + let v9_1 = ProtocolVersion::new(9, 1); + let v9_10 = ProtocolVersion::new(9, 10); + let v10_0 = ProtocolVersion::new(10, 0); + let v10_9 = ProtocolVersion::new(10, 9); + let v10_10 = ProtocolVersion::new(10, 10); + let v10_11 = ProtocolVersion::new(10, 11); + + assert!(v10_9 > v9_10); + + let from = vec![v9_0, v9_1, v9_10, v10_0, v10_9, v10_10, v10_11]; + let mut upd = from.clone(); + upd.sort(); + + assert_eq!(from, upd); + } + + #[test] + fn test_protocol_version_parsing() -> Result<()> { + let v9_0 = serde_json::from_slice::(b"{\"minor\": 0, \"major\": 9}")?; + let v9_0a = serde_json::from_slice::(b"{\"major\": 9, \"minor\": 0}")?; + let v0_9 = serde_json::from_slice::(b"{\"minor\": 9, \"major\": 0}")?; + let v0_9a = serde_json::from_slice::(b"{\"major\": 0, \"minor\": 9}")?; + + assert_eq!(v9_0, v9_0a); + assert_eq!(v0_9, v0_9a); + assert_eq!(v9_0, ProtocolVersion::new(9, 0)); + assert_eq!(v9_0.major, 9); + assert_eq!(v0_9, ProtocolVersion::new(0, 9)); + + Ok(()) + } +} diff --git a/common/src/types.rs b/common/src/types.rs index 783a9528..023fb1cd 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -1384,7 +1384,7 @@ pub struct ParameterChangeAction { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct HardForkInitiationAction { pub previous_action_id: Option, - pub protocol_version: (u64, u64), + pub protocol_version: protocol_params::ProtocolVersion, } #[serde_as] @@ -1427,6 +1427,32 @@ pub enum GovernanceAction { Information, } +impl GovernanceAction { + pub fn get_previous_action_id(&self) -> Option { + match &self { + Self::ParameterChange(ParameterChangeAction { + previous_action_id: prev, + .. + }) => prev.clone(), + Self::HardForkInitiation(HardForkInitiationAction { + previous_action_id: prev, + .. + }) => prev.clone(), + Self::TreasuryWithdrawals(_) => None, + Self::NoConfidence(prev) => prev.clone(), + Self::UpdateCommittee(UpdateCommitteeAction { + previous_action_id: prev, + .. + }) => prev.clone(), + Self::NewConstitution(NewConstitutionAction { + previous_action_id: prev, + .. + }) => prev.clone(), + Self::Information => None, + } + } +} + #[derive( serde::Serialize, serde::Deserialize, Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Hash, )] @@ -1504,6 +1530,14 @@ impl VotesCount { } } + pub fn infinity() -> Self { + Self { + committee: u64::MAX, + drep: u64::MAX, + pool: u64::MAX, + } + } + pub fn majorizes(&self, v: &VotesCount) -> bool { self.committee >= v.committee && self.drep >= v.drep && self.pool >= v.pool } @@ -1545,6 +1579,7 @@ pub enum EnactStateElem { Params(Box), Constitution(Constitution), Committee(CommitteeChange), + ProtVer(protocol_params::ProtocolVersion), NoConfidence, } diff --git a/modules/governance_state/NOTES.md b/modules/governance_state/NOTES.md index c8b2ac2c..9751ff5f 100644 --- a/modules/governance_state/NOTES.md +++ b/modules/governance_state/NOTES.md @@ -16,18 +16,46 @@ This is ok, mainnet Cardano scanners detect this and show latest vote. Other names: 'Gov Action Validity', 'govActionLifetime', updated in governance_action_validity_period parameter (measured in epochs). That is, if proposal is published in epoch E, then voting is finished at -the end of epoch E+governance_action_validity_period. +the end of epoch E+governance_action_validity_period+1. + +In another words, each action is granted 'govActionLifetime' full +epochs for voting (P is proposal, E is expiration, govActionLifetime is 6): + +'---P--|-----|-----|-----|-----|-----|-----|E' + +For +1 origin see e.g. `cardano-node/cardano-testnet/src/Testnet/Components/Query.hs`: + +``` +-- | Obtains the @govActionLifetime@ from the protocol parameters. +-- The @govActionLifetime@ or governance action maximum lifetime in epochs is +-- the number of epochs such that a governance action submitted during an epoch @e@ +-- expires if it is still not ratified as of the end of epoch: @e + govActionLifetime + 1@. +``` Default value (6) is taken from Conway Genesis, which is (in turn) taken from Cardano book: https://book.world.dev.cardano.org/environments/mainnet/conway-genesis.json +So, if voting starts at 529, gov_action_lifetime is 6, then the last epoch +when votes have meaning is 535. At the 535/536 transition all votes expire. + ### Ratification process. Ratification checked at epoch boundary. -If ratified, deposits returned immediately, actions take place at E+1/E+2 -boundary. +If ratified at E/E+1 transition, actions take place at E+1/E+2 boundary. +Rewards are paid at E+1/E+2 transition (?) Deposits transferred to reward account. +### Bootstrap period (Chang sub-era of Conway) + +Conway era is split into two parts: Chang (9.0 protocol version) and +Plomin (10.0 protocol version). The first ("Chang") epoch has limited +governance ("bootstrap governance"): + +* DReps may vote only for Info actions, they don't count for other actions. +* Only Info, ParameterChange and HardFork actions are allowed. + +https://docs.cardano.org/about-cardano/evolution/upgrades/chang + ### Genesis blocks * Conway genesis: committee key hashes have prefix 'scriptHash-' (I believe, 'keyHash-'), followed by hex hash. To be researched.... @@ -74,6 +102,7 @@ epoch. Special message? total. Need info about voting registration. * DRep::epoch -- it's written that it's epoch, which has ended. But I receive messages with this epoch in its beginning. Need to sort out. +* Implement bootstrap period (resolved). * What if voting length changes during voting process? E.g.: (a) epoch 100 voting starts, voting length is 10 epochs (b) epoch 107 voting length change to 3 enacts (e.g., because some earlier successful vote) diff --git a/modules/governance_state/src/ab_sancho_voting.json b/modules/governance_state/data/ab_sancho_voting.json similarity index 100% rename from modules/governance_state/src/ab_sancho_voting.json rename to modules/governance_state/data/ab_sancho_voting.json diff --git a/modules/governance_state/src/alonzo_babbage_voting.json b/modules/governance_state/data/alonzo_babbage_voting.json similarity index 100% rename from modules/governance_state/src/alonzo_babbage_voting.json rename to modules/governance_state/data/alonzo_babbage_voting.json diff --git a/modules/governance_state/data/check_conway_syncdb.py b/modules/governance_state/data/check_conway_syncdb.py new file mode 100644 index 00000000..94f38535 --- /dev/null +++ b/modules/governance_state/data/check_conway_syncdb.py @@ -0,0 +1,89 @@ +# Standalone test for Conway governance correctness checking +# Use: check_conway_syncdb.py + +import sys + +def screen_strings(header): + inside = False + prev = " " + out = "" + for ptr in range(0,len(header)): + if prev == '\"' and header[ptr] != '\"': + inside = not inside + + if header[ptr] == ',' and inside: + out += ';' + else: + out += header[ptr] + prev = header[ptr] + + return out + +def strip_some(s): + return s.removeprefix('Some(').removesuffix(')') + +if len(sys.argv) <= 2: + print("\nUsage: %s \n" % sys.argv[0]) + exit(1) + +dbsync = open(sys.argv[1],'rt') +acropolis = open(sys.argv[2],'rt') + +dbsync_dict = {} + +# 0 7 13 23 +header = """id,tx_id,index,prev_gov_action_proposal,deposit,return_address,expiration, + voting_anchor_id,type,description,param_proposal,ratified_epoch,enacted_epoch, + dropped_epoch,expired_epoch,id,hash,block_id,block_index,out_sum,fee,deposit,size, + invalid_before,invalid_hereafter,valid_contract,script_size,treasury_donation""" +header = screen_strings(header) +hl = header.split(',') + +for s in dbsync: + sh = screen_strings(s) + sl = sh.strip().split(',') + if len(sl) != len(hl): + continue + if sl == hl: + continue + + hhash = sl[16].strip("\\x") + + idx = (hhash,sl[2]) + if idx not in dbsync_dict: + dbsync_dict[idx] = [] + dbsync_dict[idx].append((sl[8],sl[11],sl[12],sl[13],sl[14])) + +header_a = """id,start,tx_id,index,prev_gov_action_proposal,deposit,return_address,expiration, + voting_anchor_id,type,description,param_proposal,ratified_epoch,enacted_epoch, + dropped_epoch,expired_epoch""" +al = header_a.split(',') + +found = 0 +for s in acropolis: + sh = screen_strings(s) + sl = sh.strip().split(',') + if len(sl) < 14: + print("Rejecting:",s) + continue + if sl == al: + continue + + idx = (sl[1],sl[2]) + if idx not in dbsync_dict: + print(idx," not found\n") + else: + rec = dbsync_dict[idx] + if len(rec) > 1: + print(idx, "too many records: ",rec,"\n") + + found += 1 + (ty,re,en,de,ex) = rec[0] + if ty == "InfoAction": + ty = "Information" + if ty != sl[8]: print (idx, "types do not match: `",ty,"` `",sl[8],"`\n") + if re != strip_some(sl[11]): print (idx, "re do not match: `",re,"` `",sl[11],"`\n") + if en != strip_some(sl[12]): print (idx, "en do not match: `",en,"` `",sl[12],"`\n") + if ex != strip_some(sl[14]): print (idx, "ex do not match: `",ex,"` `",sl[14],"`\n") + +print("Total found records: ",found,"\n") diff --git a/modules/governance_state/data/mysql_db_voting.csv b/modules/governance_state/data/mysql_db_voting.csv new file mode 100644 index 00000000..a5238b5f --- /dev/null +++ b/modules/governance_state/data/mysql_db_voting.csv @@ -0,0 +1,71 @@ +id,tx_id,index,prev_gov_action_proposal,deposit,return_address,expiration,voting_anchor_id,type,description,param_proposal,ratified_epoch,enacted_epoch,dropped_epoch,expired_epoch,id,hash,block_id,block_index,out_sum,fee,deposit,size,invalid_before,invalid_hereafter,valid_contract,script_size,treasury_donation +5,98477975,0,,100000000000,4563516,526,695,ParameterChange,"{""tag"": ""ParameterChange"", ""contents"": [null, {""costModels"": {""PlutusV3"": [100788, 420, 1, 1, 1000, 173, 0, 1, 1000, 59957, 4, 1, 11183, 32, 201305, 8356, 4, 16000, 100, 16000, 100, 16000, 100, 16000, 100, 16000, 100, 16000, 100, 100, 100, 16000, 100, 94375, 32, 132994, 32, 61462, 4, 72010, 178, 0, 1, 22151, 32, 91189, 769, 4, 2, 85848, 123203, 7305, -900, 1716, 549, 57, 85848, 0, 1, 1, 1000, 42921, 4, 2, 24548, 29498, 38, 1, 898148, 27279, 1, 51775, 558, 1, 39184, 1000, 60594, 1, 141895, 32, 83150, 32, 15299, 32, 76049, 1, 13169, 4, 22100, 10, 28999, 74, 1, 28999, 74, 1, 43285, 552, 1, 44749, 541, 1, 33852, 32, 68246, 32, 72362, 32, 7243, 32, 7391, 32, 11546, 32, 85848, 123203, 7305, -900, 1716, 549, 57, 85848, 0, 1, 90434, 519, 0, 1, 74433, 32, 85848, 123203, 7305, -900, 1716, 549, 57, 85848, 0, 1, 1, 85848, 123203, 7305, -900, 1716, 549, 57, 85848, 0, 1, 955506, 213312, 0, 2, 270652, 22588, 4, 1457325, 64566, 4, 20467, 1, 4, 0, 141992, 32, 100788, 420, 1, 1, 81663, 32, 59498, 32, 20142, 32, 24588, 32, 20744, 32, 25933, 32, 24623, 32, 43053543, 10, 53384111, 14333, 10, 43574283, 26308, 10, 16000, 100, 16000, 100, 962335, 18, 2780678, 6, 442008, 1, 52538055, 3756, 18, 267929, 18, 76433006, 8868, 18, 52948122, 18, 1995836, 36, 3227919, 12, 901022, 1, 166917843, 4307, 36, 284546, 36, 158221314, 26549, 36, 74698472, 36, 333849714, 1, 254006273, 72, 2174038, 72, 2261318, 64571, 4, 207616, 8310, 4, 1293828, 28716, 63, 0, 1, 1006041, 43623, 251, 0, 1, 100181, 726, 719, 0, 1, 100181, 726, 719, 0, 1, 100181, 726, 719, 0, 1, 107878, 680, 0, 1, 95336, 1, 281145, 18848, 0, 1, 180194, 159, 1, 1, 158519, 8942, 0, 1, 159378, 8813, 0, 1, 107490, 3298, 1, 106057, 655, 1, 1964219, 24520, 3]}}, ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",401,525,526,,,98477975,\xb2a591ac219ce6dcca5847e0248015209c7cb0436aa6bd6863d0c1f152a60bc5,11059483,12,1277744,366804,100000000000,3594,,,t,2132,0 +1,95815162,0,,100000000000,4870428,514,90,InfoAction,"{""tag"": ""InfoAction""}",,,,515,514,95815162,\x15f82a365bdee483a4b03873a40d3829cc88c048ff3703e11bd01dd9e035c916,10789475,12,65650430,175929,100000000000,362,,,t,0,0 +8,105650982,0,,100000000000,4563516,544,1150,NewConstitution,"{""tag"": ""NewConstitution"", ""contents"": [null, {""anchor"": {""url"": ""ipfs://bafkreiazhhawe7sjwuthcfgl3mmv2swec7sukvclu3oli7qdyz4uhhuvmy"", ""dataHash"": ""2a61e2f4b63442978140c77a70daab3961b22b12b63b13949a390c097214d1c5""}, ""script"": ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""}]}",,541,542,,,105650982,\x8c653ee5c9800e6d31e79b5a7f7d4400c81d44717ad4db633dc18d4c07e4a4fd,11428973,21,1708465,187237,100000000000,518,,,t,0,0 +2,96653159,0,,100000000000,4896630,517,443,InfoAction,"{""tag"": ""InfoAction""}",,,,518,517,96653159,\x59fd353253eb177e2104e8f23ea4c63e3d32ef95c7865d03e90d3884424dc1db,10852595,12,9823015,176985,100000000000,386,,,t,0,0 +3,97475494,0,,100000000000,4918992,521,569,InfoAction,"{""tag"": ""InfoAction""}",,,,522,521,97475494,\x7fd6429add8f2611ad8d48c0cc49101463093aec285faea402e8cfde78ea58d7,10951864,7,999827107,172893,100000000000,393,,,t,0,0 +4,98263157,0,,100000000000,4563516,525,671,ParameterChange,"{""tag"": ""ParameterChange"", ""contents"": [null, {""costModels"": {""PlutusV3"": [100788, 420, 1, 1, 1000, 173, 0, 1, 1000, 59957, 4, 1, 11183, 32, 201305, 8356, 4, 16000, 100, 16000, 100, 16000, 100, 16000, 100, 16000, 100, 16000, 100, 100, 100, 16000, 100, 94375, 32, 132994, 32, 61462, 4, 72010, 178, 0, 1, 22151, 32, 91189, 769, 4, 2, 85848, 123203, 7305, -900, 1716, 549, 57, 85848, 0, 1, 1, 1000, 42921, 4, 2, 24548, 29498, 38, 1, 898148, 27279, 1, 51775, 558, 1, 39184, 1000, 60594, 1, 141895, 32, 83150, 32, 15299, 32, 76049, 1, 13169, 4, 22100, 10, 28999, 74, 1, 28999, 74, 1, 43285, 552, 1, 44749, 541, 1, 33852, 32, 68246, 32, 72362, 32, 7243, 32, 7391, 32, 11546, 32, 85848, 123203, 7305, -900, 1716, 549, 57, 85848, 0, 1, 90434, 519, 0, 1, 74433, 32, 85848, 123203, 7305, -900, 1716, 549, 57, 85848, 0, 1, 1, 85848, 123203, 7305, -900, 1716, 549, 57, 85848, 0, 1, 955506, 213312, 0, 2, 270652, 22588, 4, 1457325, 64566, 4, 20467, 1, 4, 0, 141992, 32, 100788, 420, 1, 1, 81663, 32, 59498, 32, 20142, 32, 24588, 32, 20744, 32, 25933, 32, 24623, 32, 43053543, 10, 53384111, 14333, 10, 43574283, 26308, 10, 16000, 100, 16000, 100, 962335, 18, 2780678, 6, 442008, 1, 52538055, 3756, 18, 267929, 18, 76433006, 8868, 18, 52948122, 18, 1995836, 36, 3227919, 12, 901022, 1, 166917843, 4307, 36, 284546, 36, 158221314, 26549, 36, 74698472, 36, 333849714, 1, 254006273, 72, 2174038, 72, 2261318, 64571, 4, 207616, 8310, 4, 1293828, 28716, 63, 0, 1, 1006041, 43623, 251, 0, 1]}}, ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",400,,,526,525,98263157,\x51f495aa23f4b3b3aa90afde4a0e67823bb7ac4ac65f5ffbb138373b863f2f74,11038356,0,1644548,355452,100000000000,3441,,,t,2132,0 +6,99700949,0,,100000000000,4563516,529,754,InfoAction,"{""tag"": ""InfoAction""}",,,,530,529,99700949,\xfff0df644d328a5367212f45bab59060bde3c4091dc96c723062896fd6197314,11122159,76,1079595,198149,100000000000,560,,,t,0,0 +7,103039629,0,,100000000000,4563516,536,936,HardForkInitiation,"{""tag"": ""HardForkInitiation"", ""contents"": [null, {""major"": 10, ""minor"": 0}]}",,536,537,,,103039629,\x0b19476e40bbbb5e1e8ce153523762e2b6859e7ecacbaf06eae0ee6a447e79b9,11254748,38,895702,183893,100000000000,442,,,t,0,0 +9,106371891,0,5,100000000000,5186648,546,1302,ParameterChange,"{""tag"": ""ParameterChange"", ""contents"": [{""txId"": ""b2a591ac219ce6dcca5847e0248015209c7cb0436aa6bd6863d0c1f152a60bc5"", ""govActionIx"": 0}, {""treasuryCut"": 0.1}, ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",402,,,547,546,106371891,\x941502b0aa104c850d197923259444d2b57cab7af18b63143775465aaacc84f5,11488715,31,2992488895,323076,100000000000,2855,,147912156,t,2132,0 +10,107048539,0,,100000000000,4563516,549,1458,InfoAction,"{""tag"": ""InfoAction""}",,,,550,549,107048539,\x56f39054758f1a3cedc1de9225d66bf270b62dfdbfbc5399f1d6d43aceffc636,11554076,2,1527168,181297,100000000000,383,,,t,0,0 +11,107777670,0,,100000000000,5253767,553,1566,InfoAction,"{""tag"": ""InfoAction""}",,,,554,553,107777670,\x7f320409d9998712ff3a3cdf0c9439e1543f236a3d746766f78f1fdbe1e06bf8,11622438,9,9987445153,181913,100000000000,601,,,t,0,0 +12,108041910,0,,100000000000,4563516,554,1630,InfoAction,"{""tag"": ""InfoAction""}",,,,555,554,108041910,\x9b62b3c632f329016a968ac25211825bb4f84b12461121c7da3aa11df92370f9,11661886,14,1345871,181297,100000000000,383,,,t,0,0 +13,108980410,0,,100000000000,3391711,561,1892,InfoAction,"{""tag"": ""InfoAction""}",,,,562,561,108980410,\x7d9fc9fe4cee64fb34e57783378ac869a85c78d6fbcd4078ed131ab6fa3c7db6,11794543,12,11990791828,295653,100000000000,3187,,,t,0,0 +15,109382083,0,,100000000000,4180416,563,1969,InfoAction,"{""tag"": ""InfoAction""}",,,,564,563,109382083,\x4840e305563327358cf70dae5015b2df8f8c35cef03f74521d4f117ac17bc384,11845257,6,234865010,270001,100000000000,2600,,,t,0,0 +16,109387915,0,,100000000000,5321718,563,1973,InfoAction,"{""tag"": ""InfoAction""}",,,,564,563,109387915,\x637e3c256da9c1350847ca3211e8c44e3660a4471e8b6f68a8c537746b4aeb73,11846463,2,9993345457,177645,100000000000,501,,,t,0,0 +14,109365119,0,,100000000000,5321055,563,1961,InfoAction,"{""tag"": ""InfoAction""}",,,,564,563,109365119,\xbd488931f792651fefa9c6fda185a2c6cec83245b51d994e33090ce36e29cc26,11843663,2,2750000,250000,100002000000,1071,,,t,0,0 +17,109397627,0,,100000000000,3391711,563,1983,InfoAction,"{""tag"": ""InfoAction""}",,,,564,563,109397627,\xdefbf15b06092718adf4befeab982e03d2966b9caeef93c19e470549ef75ea49,11847866,12,12352487425,287073,100000000000,2992,,,t,0,0 +67,113657169,0,,100000000000,5473879,587,6058,InfoAction,"{""tag"": ""InfoAction""}",,,,,,113657169,\x90cf51975f9c19c291bac3e57364a89507e64daa0a2d35e356f87e6684821556,12363296,1,149823499,176501,100000000000,375,,,t,0,0 +18,109605083,0,,100000000000,5322199,564,2037,InfoAction,"{""tag"": ""InfoAction""}",,,,565,564,109605083,\xe14de8d9dc4f4ddf3fe9250a8a926e20f10e99b86bd0610b77d7a054981591ee,11870630,19,2641190,181297,100000000000,383,,,t,0,0 +66,113591364,0,,100000000000,3391711,586,6022,InfoAction,"{""tag"": ""InfoAction""}",,,,,586,113591364,\x89e3a4f09122d669d6f6c82dd894e02826e8497be7eb036233bafc0ee4fc6665,12354745,2,6609016485,334329,100000000000,4066,,,t,0,0 +22,111497194,0,,100000000000,3391711,576,2536,InfoAction,"{""tag"": ""InfoAction""}",,,,577,576,111497194,\x495bd3cd44ea6bc0b4c2dbb1e4cdc7e214874c2c07490a4e2476a627ef911280,12123162,5,133600048012,305201,100000000000,3404,,,t,0,0 +20,111300899,0,,100000000000,5423582,574,2502,InfoAction,"{""tag"": ""InfoAction""}",,,,575,574,111300899,\x9d213a57684d7ddf6f3350c80d042639ecbed5ccccc4a05bf54959a086593e7b,12093342,12,369725480,267229,100000000000,1027,,,t,0,0 +24,111863657,0,,100000000000,5443227,577,2620,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 2162096000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,574,575,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +25,111863657,1,,100000000000,5443227,577,2621,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 96817080000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,574,575,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +43,111863657,19,,100000000000,5443227,577,2639,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 605000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,577,578,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +46,111863657,22,,100000000000,5443227,577,2642,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 592780000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,577,578,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +62,112292472,0,,100000000000,5443227,580,4387,NewCommittee,"{""tag"": ""UpdateCommittee"", ""contents"": [null, [{""scriptHash"": ""b6012034ba0a7e4afbbf2c7a1432f8824aee5299a48e38e41a952686""}, {""scriptHash"": ""ce8b37a72b178a37bbd3236daa7b2c158c9d3604e7aa667e6c6004b7""}, {""scriptHash"": ""df0e83bde65416dade5b1f97e7f115cc1ff999550ad968850783fe50""}, {""scriptHash"": ""e8165b3328027ee0d74b1f07298cb092fd99aa7697a1436f5997f625""}, {""scriptHash"": ""f0dc2c00d92a45521267be2d5de1c485f6f9d14466d7e16062897cf7""}], {""keyHash-13493790d9b03483a1e1e684ea4faf1ee48a58f402574e7f2246f4d4"": 653, ""keyHash-dc0d6ef49590eb6880a50a00adde17596e6d76f7159572fa1ff85f2a"": 653, ""scriptHash-1980dbf1ad624b0cb5410359b5ab14d008561994a6c2b6c53fabec00"": 726, ""scriptHash-349e55f83e9af24813e6cb368df6a80d38951b2a334dfcdf26815558"": 653, ""scriptHash-84aebcfd3e00d0f87af918fc4b5e00135f407e379893df7e7d392c6a"": 726, ""scriptHash-9752e4306e5ae864441d21064f791174c8b626199b8e7a45f9e03b45"": 726, ""scriptHash-9cc3f387623f45dae6a68b7096b0c2e403d8601a82dc40221ead41e2"": 653}, {""numerator"": 2, ""denominator"": 3}]}",,580,581,,,112292472,\x47a0e7a4f9383b1afc2192b23b41824d65ac978d7741aca61fc1fa16833d1111,12207873,26,4805195,194805,100000000000,791,,,t,0,0 +68,114141147,0,,100000000000,4180416,589,6205,InfoAction,"{""tag"": ""InfoAction""}",,,,,,114141147,\xe5643c33f608642e329228a968770e5b19ef5f48ff1f698712e2ce864a49e3f0,12419898,0,99823499,176501,100000000000,375,,,t,0,0 +69,114195603,0,,100000000000,5556256,590,6229,InfoAction,"{""tag"": ""InfoAction""}",,,,,,114195603,\x996edfe370b8e51be73541e75499a818461305e37c7fa0c1b193f2c587167cc7,12427264,0,46833006,178437,100000000000,519,,,t,0,0 +70,114354580,0,,100000000000,5443227,591,6278,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 1150000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,,,,,114354580,\xd2db60c5307cb517c735e2d0138d2b6f10fc5b221d610fa187719bdc82af9a03,12448520,3,4487863,317332,100000000000,2788,,,t,2132,0 +71,114668785,0,8,100000000000,5321718,593,6411,NewConstitution,"{""tag"": ""NewConstitution"", ""contents"": [{""txId"": ""8c653ee5c9800e6d31e79b5a7f7d4400c81d44717ad4db633dc18d4c07e4a4fd"", ""govActionIx"": 0}, {""anchor"": {""url"": ""ipfs://bafkreibyaftvpujgjernbcj2rgrwg3fntsg37cxx5bdgpy4hyt4eki5r2e"", ""dataHash"": ""9fc568bb8ae398ff2e9b1cf7ca459c3648f865338a70248dd753aea175b0d4d4""}, ""script"": ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""}]}",,,,,,114668785,\xc882f194684d672316212f01efc6d28177e8965b7cd6956981fe37cc6715961e,12492094,6,99816195,183805,100000000000,646,,,t,0,0 +27,111863657,3,,100000000000,5443227,577,2623,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 424800000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +51,111863657,27,,100000000000,5443227,577,2647,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 1500000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,,,578,577,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +54,111863657,30,,100000000000,5443227,577,2650,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 3000000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,,,578,577,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +52,111863657,28,,100000000000,5443227,577,2648,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 3126000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,577,578,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +53,111863657,29,,100000000000,5443227,577,2649,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 889500000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,577,578,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +59,111863657,35,,100000000000,5443227,577,2655,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 750000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,577,578,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +63,112437920,0,,100000000000,5473879,580,4832,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""keyHash"": ""28e35801c889b56600b218e29080235e3172f6da9fa06b0d6e0cb049""}}, 5000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,,,581,580,112437920,\x4ff43f1eab5252ef00ba6f1429dc23715e3899834f10c067e8065c8364d5559a,12223934,17,22944868,305132,100000000000,2724,,,t,2132,0 +19,111039533,0,,100000000000,5321055,573,2466,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""860ee0f6bd8235842a908afd86dc949c4c9dabd74b0965c364b8d315""}}, 100000000000], [{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""877f57e0bdcc8167e984dee052d8dd7346effc08ff80a29b045e1a10""}}, 500000000000], [{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""9beae6fc7feada6ccf824554b5e3a498eab15205ac9248c3fb993b5f""}}, 300000000000], [{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""a7966878550ce11ec8a83b93fc1a6e105d544f78494401066c4fe0cf""}}, 300000000000], [{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""e425984e24fb2c06ad676882178ddee6e47b994a589ae3d70c817c79""}}, 300000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,570,571,,,111039533,\x60ed6ab43c840ff888a8af30a1ed27b41e9f4a91a89822b2b63d1bfc52aeec45,12057260,5,49656796,343204,100000000000,3533,159148801,,t,2132,0 +49,111863657,25,,100000000000,5443227,577,2645,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 6000000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,576,577,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +50,111863657,26,,100000000000,5443227,577,2646,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 12000000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,576,577,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +47,111863657,23,,100000000000,5443227,577,2643,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 69459000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,574,575,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +64,112439116,0,,100000000000,5473879,580,4834,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""keyHash"": ""28e35801c889b56600b218e29080235e3172f6da9fa06b0d6e0cb049""}}, 5000000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,,,581,580,112439116,\x1d6aea56e6a523b13e03ae30ff24ebf9852543b4f7d415c7e50f55f6baaa4e3d,12224102,1,39261128,308740,100000000000,2806,,,t,2132,0 +65,112509795,0,8,100000000000,5321718,581,5001,NewConstitution,"{""tag"": ""NewConstitution"", ""contents"": [{""txId"": ""8c653ee5c9800e6d31e79b5a7f7d4400c81d44717ad4db633dc18d4c07e4a4fd"", ""govActionIx"": 0}, {""anchor"": {""url"": ""ipfs://bafkreiat3w662d6jnsuz2kpra2h5ve4xxij4jkl7kylf7jk6gw43q5b5ny"", ""dataHash"": ""170379f4c41a1833743837770e5bdb034c089a8edc835174e73a9c5b692676cc""}, ""script"": ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""}]}",,,,582,581,112509795,\x207b226e110e13bb18b119fcd313520e0fcd060b2bc9fb9a5e5bc6e94ab10f3b,12233245,2,10016517356,183981,100000000000,650,,,t,0,0 +23,111783541,0,,100000000000,5443227,577,2597,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 45217000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111783541,\x3cf29192a0ee1a77985054072edcdb566ac14707730637c4635d8fb6813cb4c9,12152955,0,9688696,311304,100000000000,2756,,,t,2132,0 +61,111864094,0,,100000000000,5443227,577,2657,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 99600000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111864094,\x2c7f900b7ff68f317a7b0e42231d4aed36227660baf2ee9a4be7e880eb977313,12159572,8,7768942,317332,100000000000,2788,,,t,2132,0 +26,111863657,2,,100000000000,5443227,577,2622,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 1300000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +28,111863657,4,,100000000000,5443227,577,2624,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 220914000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +29,111863657,5,,100000000000,5443227,577,2625,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 220914000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +30,111863657,6,,100000000000,5443227,577,2626,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 130903000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +31,111863657,7,,100000000000,5443227,577,2627,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 1161000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +32,111863657,8,,100000000000,5443227,577,2628,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 220914000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +33,111863657,9,,100000000000,5443227,577,2629,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 300000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +34,111863657,10,,100000000000,5443227,577,2630,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 600000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +35,111863657,11,,100000000000,5443227,577,2631,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 5885000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +36,111863657,12,,100000000000,5443227,577,2632,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 578571000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +37,111863657,13,,100000000000,5443227,577,2633,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 243478000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +38,111863657,14,,100000000000,5443227,577,2634,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 11070323000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +39,111863657,15,,100000000000,5443227,577,2635,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 700000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +40,111863657,16,,100000000000,5443227,577,2636,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 583000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +41,111863657,17,,100000000000,5443227,577,2637,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 657692000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +42,111863657,18,,100000000000,5443227,577,2638,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 266667000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +44,111863657,20,,100000000000,5443227,577,2640,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 212000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +45,111863657,21,,100000000000,5443227,577,2641,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 15750000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +48,111863657,24,,100000000000,5443227,577,2644,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 6000000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +55,111863657,31,,100000000000,5443227,577,2651,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 4000000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +56,111863657,32,,100000000000,5443227,577,2652,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 26840000000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +57,111863657,33,,100000000000,5443227,577,2653,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 199911000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +58,111863657,34,,100000000000,5443227,577,2654,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 314800000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 +60,111863657,36,,100000000000,5443227,577,2656,TreasuryWithdrawals,"{""tag"": ""TreasuryWithdrawals"", ""contents"": [[[{""network"": ""Mainnet"", ""credential"": {""scriptHash"": ""8583857e4a12ffe1e6f641a1785a0f2f036c565cfbe6ff9db8e5a469""}}, 104347000000]], ""fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64""]}",,575,576,,,111863657,\x8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,12159549,11,99998397578,1602422,3700000000000,11159,,,t,2132,0 diff --git a/modules/governance_state/data/retrieve.sql b/modules/governance_state/data/retrieve.sql new file mode 100644 index 00000000..e5112952 --- /dev/null +++ b/modules/governance_state/data/retrieve.sql @@ -0,0 +1 @@ +\copy (select * from gov_action_proposal left join tx on gov_action_proposal.tx_id = tx.id) to 'mysql_db_voting.csv' csv header diff --git a/modules/governance_state/src/alonzo_babbage_voting.rs b/modules/governance_state/src/alonzo_babbage_voting.rs index bc90a45b..46c9a4f7 100644 --- a/modules/governance_state/src/alonzo_babbage_voting.rs +++ b/modules/governance_state/src/alonzo_babbage_voting.rs @@ -106,6 +106,10 @@ impl AlonzoBabbageVoting { pub fn advance_epoch(&mut self, epoch_blk: &BlockInfo) { self.proposals.retain(|enact_epoch, _| *enact_epoch >= epoch_blk.epoch); } + + pub fn get_stats(&self) -> String { + format!("alonzo proposal epochs: {:?}", self.proposals.keys()) + } } #[cfg(test)] @@ -211,7 +215,7 @@ mod tests { // Mainnet Tests // - const MAINNET_PROPOSALS_JSON: &[u8] = include_bytes!("./alonzo_babbage_voting.json"); + const MAINNET_PROPOSALS_JSON: &[u8] = include_bytes!("../data/alonzo_babbage_voting.json"); fn extract_mainnet_parameter( f: impl Fn(&ProtocolParamUpdate) -> Option, @@ -310,7 +314,7 @@ mod tests { // SanchoNet Tests // - const SANCHONET_PROPOSALS_JSON: &[u8] = include_bytes!("./ab_sancho_voting.json"); + const SANCHONET_PROPOSALS_JSON: &[u8] = include_bytes!("../data/ab_sancho_voting.json"); fn extract_sanchonet_parameter( f: impl Fn(&ProtocolParamUpdate) -> Option, diff --git a/modules/governance_state/src/conway_voting.rs b/modules/governance_state/src/conway_voting.rs new file mode 100644 index 00000000..c67cbbd8 --- /dev/null +++ b/modules/governance_state/src/conway_voting.rs @@ -0,0 +1,606 @@ +use crate::voting_state::VotingRegistrationState; +use acropolis_common::protocol_params::ConwayParams; +use acropolis_common::{ + BlockInfo, DRepCredential, DelegatedStake, EnactStateElem, GovActionId, GovernanceAction, + GovernanceOutcome, GovernanceOutcomeVariant, KeyHash, Lovelace, ProposalProcedure, + SingleVoterVotes, TreasuryWithdrawalsAction, TxHash, Vote, Voter, VotesCount, VotingOutcome, + VotingProcedure, +}; +use anyhow::{anyhow, bail, Result}; +use hex::ToHex; +use std::collections::{HashMap, HashSet}; +use std::fs::OpenOptions; +use std::io::Write; +use std::ops::Range; +use tracing::{debug, error, info}; + +#[derive(Debug)] +pub struct ActionStatus { + voting_epochs: Range, + ratification_epoch: Option, + enactment_epoch: Option, + expiration_epoch: Option, +} + +impl ActionStatus { + pub fn new(current_epoch: u64, voting_length: u64) -> Self { + Self { + voting_epochs: current_epoch..current_epoch + voting_length + 1, + ratification_epoch: None, + enactment_epoch: None, + expiration_epoch: None, + } + } + + pub fn is_active(&self, current_epoch: u64) -> bool { + self.voting_epochs.contains(¤t_epoch) + } + + pub fn is_accepted(&self) -> bool { + self.ratification_epoch.is_some() + } +} + +pub struct ConwayVoting { + conway: Option, + bootstrap: Option, + + pub proposals: HashMap, + pub votes: HashMap>, + action_status: HashMap, + + verification_output_file: Option, + action_proposal_count: usize, + votes_count: usize, +} + +impl ConwayVoting { + pub fn new(verification_output_file: Option) -> Self { + Self { + conway: None, + bootstrap: None, + proposals: Default::default(), + votes: Default::default(), + action_status: Default::default(), + action_proposal_count: 0, + votes_count: 0, + verification_output_file, + } + } + + pub fn get_conway_params(&self) -> Result<&ConwayParams> { + self.conway.as_ref().ok_or_else(|| anyhow!("Conway parameters not available")) + } + + pub fn update_parameters(&mut self, conway: &Option, bootstrap: bool) { + self.conway = conway.clone(); + self.bootstrap = Some(bootstrap); + } + + pub fn insert_proposal_procedure( + &mut self, + epoch: u64, + proc: &ProposalProcedure, + ) -> Result<()> { + self.action_proposal_count += 1; + let prev = self.proposals.insert(proc.gov_action_id.clone(), (epoch, proc.clone())); + if let Some(prev) = prev { + return Err(anyhow!( + "Governance procedure {} already exists! New: {:?}, old: {:?}", + proc.gov_action_id, + (epoch, proc), + prev + )); + } + + let prev = self.action_status.insert( + proc.gov_action_id.clone(), + ActionStatus::new(epoch, self.get_conway_params()?.gov_action_lifetime as u64), + ); + if let Some(prev) = prev { + return Err(anyhow!( + "Governance procedure {} action status already exists! Old: {:?}", + proc.gov_action_id, + prev + )); + } + + Ok(()) + } + + /// Update votes memory cache + pub fn insert_voting_procedure( + &mut self, + current_epoch: u64, + voter: &Voter, + transaction: &TxHash, + voter_votes: &SingleVoterVotes, + ) -> Result<()> { + self.votes_count += voter_votes.voting_procedures.len(); + for (action_id, procedure) in voter_votes.voting_procedures.iter() { + let votes = self.votes.entry(action_id.clone()).or_insert_with(|| HashMap::new()); + + match self.action_status.get(action_id) { + None => { + error!( + "Governance vote by {} for non-registered {}. Ignored.", + voter, action_id + ); + continue; + } + Some(vs) if !vs.is_active(current_epoch) => { + error!( + "Governance vote by {} for inactive {}. Active at {:?}. Ignored.", + voter, action_id, vs.voting_epochs + ); + continue; + } + Some(_) => (), + } + + if let Some((prev_trans, prev_vote)) = + votes.insert(voter.clone(), (transaction.clone(), procedure.clone())) + { + // Re-voting is allowed; new vote must be treated as the proper one, + // older is to be discarded. + if tracing::enabled!(tracing::Level::DEBUG) { + debug!("Governance vote by {} for {} already registered! New: {:?}, old: {:?} from {}", + voter, action_id, procedure, prev_vote, prev_trans.encode_hex::() + ); + } + } + } + Ok(()) + } + + /// Checks whether action_id can be considered finally accepted + fn is_finally_accepted( + &self, + voting_state: &VotingRegistrationState, + action_id: &GovActionId, + drep_stake: &HashMap, + spo_stake: &HashMap, + ) -> Result { + let (_epoch, proposal) = self + .proposals + .get(action_id) + .ok_or_else(|| anyhow!("action {} not found", action_id))?; + let conway_params = self.get_conway_params()?; + let bootstrap = self.bootstrap.ok_or_else(|| anyhow!("'bootstrap' param not set"))?; + let threshold = voting_state.get_action_thresholds(proposal, conway_params, bootstrap)?; + + let votes = self.get_actual_votes(action_id, drep_stake, spo_stake); + let voted = votes.majorizes(&threshold); + let previous_ok = match proposal.gov_action.get_previous_action_id() { + Some(act) => self.action_status.get(&act).map(|x| x.is_accepted()).unwrap_or(false), + None => true, + }; + let accepted = previous_ok && voted; + info!( + "Proposal {action_id}: votes {votes}, thresholds {threshold}, prevous_ok {previous_ok}, \ + voted {voted}, result {accepted}" + ); + + Ok(VotingOutcome { + procedure: proposal.clone(), + votes_cast: votes, + votes_threshold: threshold, + accepted, + }) + } + + /// Should be called when voting is over + fn end_voting(&mut self, action_id: &GovActionId) -> Result<()> { + self.votes.remove(&action_id); + self.proposals.remove(&action_id); + + Ok(()) + } + + /// Returns actual votes: (Pool votes, DRep votes, committee votes) + fn get_actual_votes( + &self, + action_id: &GovActionId, + drep_stake: &HashMap, + spo_stake: &HashMap, + ) -> VotesCount { + let mut votes = VotesCount::zero(); + if let Some(all_votes) = self.votes.get(&action_id) { + for (voter, (_hash, voting_proc)) in all_votes.iter() { + if voting_proc.vote != Vote::Yes { + // TODO: correctly count abstain votes + count vote pools + continue; + } + + match voter { + Voter::ConstitutionalCommitteeKey(_) => votes.committee += 1, + Voter::ConstitutionalCommitteeScript(_) => votes.committee += 1, + Voter::DRepKey(key) => { + drep_stake + .get(&DRepCredential::AddrKeyHash(key.clone())) + .inspect(|v| votes.drep += *v); + } + Voter::DRepScript(script) => { + drep_stake + .get(&DRepCredential::ScriptHash(script.clone())) + .inspect(|v| votes.drep += *v); + } + Voter::StakePoolKey(pool) => { + spo_stake.get(pool).inspect(|ds| votes.pool += ds.live); + } + } + } + } + votes + } + + /// Checks whether action is expired at the beginning of new_epoch + fn is_expired(&self, new_epoch: u64, action_id: &GovActionId) -> Result { + info!( + "Checking whether {} is expired at new epoch {}", + action_id, new_epoch + ); + + let action_status = self + .action_status + .get(action_id) + .ok_or_else(|| anyhow!("Action status {action_id} not found"))?; + + Ok(!action_status.is_active(new_epoch)) + } + + fn pack_as_enact_state_elem(p: &ProposalProcedure) -> Option { + match &p.gov_action { + GovernanceAction::Information => None, + GovernanceAction::TreasuryWithdrawals(_wt) => None, + GovernanceAction::HardForkInitiation(hf) => { + Some(EnactStateElem::ProtVer(hf.protocol_version.clone())) + } + GovernanceAction::ParameterChange(pc) => { + Some(EnactStateElem::Params(pc.protocol_param_update.clone())) + } + GovernanceAction::NewConstitution(nc) => { + Some(EnactStateElem::Constitution(nc.new_constitution.clone())) + } + GovernanceAction::UpdateCommittee(uc) => { + Some(EnactStateElem::Committee(uc.data.clone())) + } + GovernanceAction::NoConfidence(_) => Some(EnactStateElem::NoConfidence), + } + } + + fn retrieve_withdrawal(p: &ProposalProcedure) -> Option { + if let GovernanceAction::TreasuryWithdrawals(ref action) = p.gov_action { + Some(action.clone()) + } else { + None + } + } + + /// Checks and updates action_id state at the start of new_epoch + /// If the action is accepted, returns accepted ProposalProcedure. + fn process_one_proposal( + &mut self, + new_epoch: u64, + voting_state: &VotingRegistrationState, + action_id: &GovActionId, + drep_stake: &HashMap, + spo_stake: &HashMap, + ) -> Result> { + let outcome = self.is_finally_accepted(voting_state, &action_id, drep_stake, spo_stake)?; + let expired = self.is_expired(new_epoch, &action_id)?; + if outcome.accepted || expired { + self.end_voting(&action_id)?; + info!( + "New epoch {new_epoch}: voting for {action_id} outcome: {}, expired: {expired}", + outcome.accepted + ); + return Ok(Some(outcome)); + } + + Ok(None) + } + + fn gov_action_id_to_string(action_id: &GovActionId) -> String { + format!( + "\"transaction: {}, action_index: {}\"", + hex::encode(action_id.transaction_id), + action_id.action_index + ) + } + + fn get_action_name(action: &GovernanceAction) -> &str { + match action { + GovernanceAction::ParameterChange(_) => "ParameterChange", + GovernanceAction::HardForkInitiation(_) => "HardForkInitiation", + GovernanceAction::TreasuryWithdrawals(_) => "TreasuryWithdrawals", + GovernanceAction::NoConfidence(_) => "NoConfidence", + GovernanceAction::UpdateCommittee(_) => "UpdateCommittee", + GovernanceAction::NewConstitution(_) => "NewConstitution", + GovernanceAction::Information => "Information", + } + } + + fn prepare_quotes(input: &str) -> String { + input.replace("\"", "\"\"") + } + + /// Function dumps information about completed (expired, ratified, enacted) governance + /// actions in format, close to that of `gov_action_proposal` from `sqldb`. + pub fn print_outcome_to_verify(&self, outcome: &Vec) -> Result<()> { + let out_file_name = match &self.verification_output_file { + Some(o) => o, + None => return Ok(()), + }; + + let mut out_file = match OpenOptions::new().append(true).open(out_file_name.clone()) { + Ok(res) => res, + Err(e) => bail!("Cannot open verification output {out_file_name} for writing: {e}"), + }; + + // If there is no outcome, the file will be created (appended), but not changed. + // This is intentional for ease of debugging. + for elem in outcome.iter() { + let prev_action = match &elem.voting.procedure.gov_action.get_previous_action_id() { + Some(act) => Self::gov_action_id_to_string(act), + None => "".to_owned(), + }; + + let action_status = + self.action_status.get(&elem.voting.procedure.gov_action_id).ok_or_else(|| { + anyhow!( + "Cannot get action status for {}", + &elem.voting.procedure.gov_action_id + ) + })?; + + let deposit = &elem.voting.procedure.deposit; + let reward = hex::encode(elem.voting.procedure.reward_account.to_vec()); + let expire = action_status.voting_epochs.end; + let ratification_info = if elem.voting.accepted { + format!( + "{:?},{:?},,", + action_status.ratification_epoch, action_status.enactment_epoch + ) + } else { + format!(",,,{:?}", action_status.expiration_epoch) + }; + let txid: String = elem.voting.procedure.gov_action_id.transaction_id.encode_hex(); + let idx = elem.voting.procedure.gov_action_id.action_index; + let ptype = Self::get_action_name(&elem.voting.procedure.gov_action); + let proc = Self::prepare_quotes(&format!("{:?}", &elem.voting.procedure.gov_action)); + let cast = &elem.voting.votes_cast; + let threshold = &elem.voting.votes_threshold; + + // id,tx_id,index,prev_gov_action_proposal,deposit,return_address,expiration, + // voting_anchor_id,type,description,param_proposal,ratified_epoch,enacted_epoch, + // dropped_epoch,expired_epoch,votes_cast,votes_threshold + let res = format!( + "{},{txid},{idx},{prev_action},{deposit},{reward},{expire},,{ptype},\"{proc}\",,\ + {ratification_info},{cast},{threshold}\n", + elem.voting.procedure.gov_action_id + ); + if let Err(e) = out_file.write(&res.as_bytes()) { + error!( + "Cannot write 'res' to verification output {out_file_name} for writing: {e}" + ); + } + } + + Ok(()) + } + + pub fn finalize_conway_voting( + &mut self, + new_block: &BlockInfo, + voting_state: &VotingRegistrationState, + drep_stake: &HashMap, + spo_stake: &HashMap, + ) -> Result> { + let mut outcome = Vec::::new(); + let actions = self.proposals.keys().map(|a| a.clone()).collect::>(); + + for action_id in actions.iter() { + info!( + "Epoch {} started: processing action {}", + new_block.epoch, action_id + ); + let one_outcome = match self.process_one_proposal( + new_block.epoch, + &voting_state, + &action_id, + drep_stake, + spo_stake, + ) { + Err(e) => { + error!("Error processing governance {action_id}: {e}"); + continue; + } + Ok(None) => continue, + Ok(Some(out)) if out.accepted => { + let mut action_to_perform = GovernanceOutcomeVariant::NoAction; + + if let Some(elem) = Self::pack_as_enact_state_elem(&out.procedure) { + action_to_perform = GovernanceOutcomeVariant::EnactStateElem(elem); + } else if let Some(wt) = Self::retrieve_withdrawal(&out.procedure) { + action_to_perform = GovernanceOutcomeVariant::TreasuryWithdrawal(wt); + } + + GovernanceOutcome { + voting: out, + action_to_perform, + } + } + Ok(Some(out)) => GovernanceOutcome { + voting: out, + action_to_perform: GovernanceOutcomeVariant::NoAction, + }, + }; + + outcome.push(one_outcome); + } + + Ok(outcome) + } + + pub fn log_conway_voting_stats(&self) { + info!("*** Current voting stats: ***"); + let mut proposal_procedures = + self.proposals.keys().cloned().collect::>(); + for (action_id, voting_procedure) in self.votes.iter() { + let proposal = match self.proposals.get(action_id) { + None => " (absent) ".to_string(), + Some(p) => { + proposal_procedures.remove(action_id); + format!(" {p:?} ") + } + }; + info!("{action_id}: {proposal} => {voting_procedure:?}",) + } + + if !proposal_procedures.is_empty() { + let pp = proposal_procedures.into_iter().map(|x| format!("{x},")).collect::(); + info!("Proposal procedures without 'votes' records: [{}]", pp); + } + info!("*** End of voting stats ***"); + } + + /// Processes final `outcomes`, checks ratification/enaction epochs, + /// updates `action_status` data structrure. + pub fn update_action_status_with_outcomes( + &mut self, + epoch: u64, + outcomes: &Vec, + ) -> Result<()> { + for one_outcome in outcomes.iter() { + let action_id = &one_outcome.voting.procedure.gov_action_id; + let action = self + .action_status + .get_mut(action_id) + .ok_or_else(|| anyhow!("Cannot get action status for {action_id}"))?; + + if one_outcome.voting.accepted { + action.ratification_epoch = Some(epoch); + action.enactment_epoch = Some(epoch + 1); + } else { + if action.is_active(epoch) { + bail!( + "Impossible outcome: {action_id} votes {:?}, not ended at {epoch}", + action.voting_epochs + ); + } + action.expiration_epoch = Some(epoch); + } + } + Ok(()) + } + + pub fn get_stats(&self) -> String { + format!( + "conway proposals: {}, conway votes: {}", + self.proposals.len(), + self.votes.len() + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use acropolis_common::Anchor; + + fn create_governance_outcome(id: u8) -> GovernanceOutcome { + let votes = VotesCount { + committee: 1, + drep: 1, + pool: 1, + }; + + let v = VotingOutcome { + procedure: ProposalProcedure { + deposit: 0, + reward_account: vec![], + gov_action_id: GovActionId { + transaction_id: [0; 32], + action_index: id, + }, + gov_action: GovernanceAction::Information, + anchor: Anchor { + url: "".to_owned(), + data_hash: Vec::new(), + }, + }, + votes_cast: votes.clone(), + votes_threshold: votes.clone(), + accepted: true, + }; + + GovernanceOutcome { + voting: v, + action_to_perform: GovernanceOutcomeVariant::NoAction, + } + } + + #[test] + fn test_outcomes_queue() -> Result<()> { + let mut voting = ConwayVoting::new(None); + let oc1 = create_governance_outcome(1); + voting.action_status.insert( + oc1.voting.procedure.gov_action_id.clone(), + ActionStatus { + voting_epochs: 0..4, + ratification_epoch: None, + enactment_epoch: None, + expiration_epoch: None, + }, + ); + + voting.update_action_status_with_outcomes(0, &vec![])?; + voting.update_action_status_with_outcomes(1, &vec![oc1.clone()])?; + assert_eq!( + voting + .action_status + .get(&oc1.voting.procedure.gov_action_id) + .unwrap() + .ratification_epoch, + Some(1) + ); + assert_eq!( + voting.action_status.get(&oc1.voting.procedure.gov_action_id).unwrap().enactment_epoch, + Some(2) + ); + + let oc2 = create_governance_outcome(2); + voting.action_status.insert( + oc2.voting.procedure.gov_action_id.clone(), + ActionStatus { + voting_epochs: 0..5, + ratification_epoch: None, + enactment_epoch: None, + expiration_epoch: None, + }, + ); + voting.update_action_status_with_outcomes(2, &vec![oc2.clone()])?; + assert_eq!( + voting + .action_status + .get(&oc2.voting.procedure.gov_action_id) + .unwrap() + .ratification_epoch, + Some(2) + ); + assert_eq!( + voting.action_status.get(&oc2.voting.procedure.gov_action_id).unwrap().enactment_epoch, + Some(3) + ); + Ok(()) + } + + #[test] + fn test_prepare_quotes() -> Result<()> { + let x = "\"A\"\" lot (\"of\") quotes\""; + let xx = ConwayVoting::prepare_quotes(x); + assert_eq!(xx, "\"\"A\"\"\"\" lot (\"\"of\"\") quotes\"\""); + Ok(()) + } +} diff --git a/modules/governance_state/src/governance_state.rs b/modules/governance_state/src/governance_state.rs index 3e38c524..eae19f48 100644 --- a/modules/governance_state/src/governance_state.rs +++ b/modules/governance_state/src/governance_state.rs @@ -20,8 +20,10 @@ use tokio::sync::Mutex; use tracing::{error, info, info_span, Instrument}; mod alonzo_babbage_voting; +mod conway_voting; mod state; mod voting_state; + use state::State; use voting_state::VotingRegistrationState; @@ -34,6 +36,8 @@ const DEFAULT_PROTOCOL_PARAMETERS_TOPIC: (&str, &str) = ("protocol-parameters-topic", "cardano.protocol.parameters"); const DEFAULT_ENACT_STATE_TOPIC: (&str, &str) = ("enact-state-topic", "cardano.enact.state"); +const VERIFICATION_OUTPUT_FILE: &str = "verification-output-file"; + /// Governance State module #[module( message_type(Message), @@ -49,6 +53,7 @@ pub struct GovernanceStateConfig { protocol_parameters_topic: String, enact_state_topic: String, governance_query_topic: String, + verification_output_file: Option, } impl GovernanceStateConfig { @@ -66,6 +71,10 @@ impl GovernanceStateConfig { protocol_parameters_topic: Self::conf(config, DEFAULT_PROTOCOL_PARAMETERS_TOPIC), enact_state_topic: Self::conf(config, DEFAULT_ENACT_STATE_TOPIC), governance_query_topic: Self::conf(config, DEFAULT_GOVERNANCE_QUERY_TOPIC), + verification_output_file: config + .get_string(VERIFICATION_OUTPUT_FILE) + .map(|x| Some(x)) + .unwrap_or(None), }) } } @@ -134,6 +143,7 @@ impl GovernanceState { let state = Arc::new(Mutex::new(State::new( context.clone(), config.enact_state_topic.clone(), + config.verification_output_file.clone(), ))); // Ticker to log stats diff --git a/modules/governance_state/src/state.rs b/modules/governance_state/src/state.rs index dcb0dc27..fc80f649 100644 --- a/modules/governance_state/src/state.rs +++ b/modules/governance_state/src/state.rs @@ -1,61 +1,54 @@ //! Acropolis Governance State: State storage -use crate::alonzo_babbage_voting::AlonzoBabbageVoting; -use crate::VotingRegistrationState; use acropolis_common::{ messages::{ CardanoMessage, DRepStakeDistributionMessage, GovernanceOutcomesMessage, GovernanceProceduresMessage, Message, ProtocolParamsMessage, SPOStakeDistributionMessage, }, - protocol_params::ConwayParams, - BlockInfo, DRepCredential, DelegatedStake, EnactStateElem, Era, GovActionId, GovernanceAction, - GovernanceOutcome, GovernanceOutcomeVariant, KeyHash, Lovelace, ProposalProcedure, - SingleVoterVotes, TreasuryWithdrawalsAction, TxHash, Voter, VotesCount, VotingOutcome, - VotingProcedure, + BlockInfo, DRepCredential, DelegatedStake, Era, GovActionId, KeyHash, Lovelace, + ProposalProcedure, TxHash, Voter, VotingProcedure, }; use anyhow::{anyhow, bail, Result}; use caryatid_sdk::Context; use hex::ToHex; use std::{collections::HashMap, sync::Arc}; -use tracing::{debug, error, info}; +use tracing::{error, info}; + +use crate::{ + alonzo_babbage_voting::AlonzoBabbageVoting, conway_voting::ConwayVoting, + VotingRegistrationState, +}; pub struct State { pub enact_state_topic: String, pub context: Arc>, - proposal_count: usize, - - pub action_proposal_count: usize, - pub votes_count: usize, pub drep_stake_messages_count: usize, current_era: Era, - conway: Option, drep_stake: HashMap, spo_stake: HashMap, alonzo_babbage_voting: AlonzoBabbageVoting, - proposals: HashMap, - votes: HashMap>, + conway_voting: ConwayVoting, } impl State { - pub fn new(context: Arc>, enact_state_topic: String) -> Self { + pub fn new( + context: Arc>, + enact_state_topic: String, + verification_output_file: Option, + ) -> Self { Self { context, enact_state_topic, - proposal_count: 0, - action_proposal_count: 0, - votes_count: 0, drep_stake_messages_count: 0, - conway: None, current_era: Era::default(), alonzo_babbage_voting: AlonzoBabbageVoting::default(), - proposals: HashMap::new(), - votes: HashMap::new(), + conway_voting: ConwayVoting::new(verification_output_file), drep_stake: HashMap::new(), spo_stake: HashMap::new(), @@ -77,11 +70,15 @@ impl State { &mut self, message: &ProtocolParamsMessage, ) -> Result<()> { - if let Some(p) = &message.params.shelley { - self.alonzo_babbage_voting.update_parameters(p.epoch_length, p.update_quorum); - } - if message.params.conway.is_some() { - self.conway = message.params.conway.clone(); + if let Some(ps) = &message.params.shelley { + self.alonzo_babbage_voting.update_parameters(ps.epoch_length, ps.update_quorum); + + if message.params.conway.is_some() { + let bootstrap = ps.protocol_params.protocol_version.is_chang()?; + self.conway_voting.update_parameters(&message.params.conway, bootstrap) + } + } else if message.params.conway.is_some() { + bail!("Impossible parameters combination: Shelley is missing, but Conway is present."); } Ok(()) @@ -124,15 +121,19 @@ impl State { } else { // Conway governance for pproc in &governance_message.proposal_procedures { - self.proposal_count += 1; - if let Err(e) = self.insert_proposal_procedure(block.epoch, pproc) { + if let Err(e) = self.conway_voting.insert_proposal_procedure(block.epoch, pproc) { error!("Error handling governance_message: '{}'", e); } } for (trans, vproc) in &governance_message.voting_procedures { for (voter, voter_votes) in vproc.votes.iter() { - if let Err(e) = self.insert_voting_procedure(voter, trans, voter_votes) { + if let Err(e) = self.conway_voting.insert_voting_procedure( + block.epoch, + voter, + trans, + voter_votes, + ) { error!( "Error handling governance voting block {}, trans {}: '{}'", block.number, @@ -140,223 +141,17 @@ impl State { e ); } - self.votes_count += voter_votes.voting_procedures.len(); - } - } - } - - Ok(()) - } - - pub fn get_conway_params(&self) -> Result<&ConwayParams> { - self.conway.as_ref().ok_or_else(|| anyhow!("Conway parameters not available")) - } - - #[allow(dead_code)] - fn have_committee(&self) -> bool { - !self.conway.iter().any(|c| c.committee.is_empty()) - } - - /// Update proposals memory cache - fn insert_proposal_procedure(&mut self, epoch: u64, proc: &ProposalProcedure) -> Result<()> { - self.action_proposal_count += 1; - let prev = self.proposals.insert(proc.gov_action_id.clone(), (epoch, proc.clone())); - if let Some(prev) = prev { - return Err(anyhow!( - "Governance procedure {} already exists! New: {:?}, old: {:?}", - proc.gov_action_id, - (epoch, proc), - prev - )); - } - Ok(()) - } - - /// Update votes memory cache - fn insert_voting_procedure( - &mut self, - voter: &Voter, - transaction: &TxHash, - voter_votes: &SingleVoterVotes, - ) -> Result<()> { - for (action_id, procedure) in voter_votes.voting_procedures.iter() { - let votes = self.votes.entry(action_id.clone()).or_insert_with(|| HashMap::new()); - if let Some((prev_trans, prev_vote)) = - votes.insert(voter.clone(), (transaction.clone(), procedure.clone())) - { - // Re-voting is allowed; new vote must be treated as the proper one, - // older is to be discarded. - if tracing::enabled!(tracing::Level::DEBUG) { - debug!("Governance vote by {} for {} already registered! New: {:?}, old: {:?} from {}", - voter, action_id, procedure, prev_vote, prev_trans.encode_hex::() - ); } } } - Ok(()) - } - - /// Checks whether action_id can be considered finally accepted - fn is_finally_accepted( - &self, - voting_state: &VotingRegistrationState, - action_id: &GovActionId, - ) -> Result { - let (_epoch, proposal) = self - .proposals - .get(action_id) - .ok_or_else(|| anyhow!("action {} not found", action_id))?; - let conway_params = self.get_conway_params()?; - let threshold = voting_state.get_action_thresholds(proposal, conway_params)?; - - let votes = self.get_actual_votes(action_id); - let accepted = votes.majorizes(&threshold); - info!("Proposal {action_id}: votes {votes}, thresholds {threshold}, result {accepted}"); - - Ok(VotingOutcome { - procedure: proposal.clone(), - votes_cast: votes, - votes_threshold: threshold, - accepted, - }) - } - - /// Should be called when voting is over - fn end_voting(&mut self, action_id: &GovActionId) -> Result<()> { - self.votes.remove(&action_id); - self.proposals.remove(&action_id); Ok(()) } - /// Returns actual votes: (Pool votes, DRep votes, committee votes) - fn get_actual_votes(&self, action_id: &GovActionId) -> VotesCount { - let mut votes = VotesCount::zero(); - if let Some(all_votes) = self.votes.get(&action_id) { - for voter in all_votes.keys() { - match voter { - Voter::ConstitutionalCommitteeKey(_) => votes.committee += 1, - Voter::ConstitutionalCommitteeScript(_) => votes.committee += 1, - Voter::DRepKey(key) => { - self.drep_stake - .get(&DRepCredential::AddrKeyHash(key.clone())) - .inspect(|v| votes.drep += *v); - } - Voter::DRepScript(script) => { - self.drep_stake - .get(&DRepCredential::ScriptHash(script.clone())) - .inspect(|v| votes.drep += *v); - } - Voter::StakePoolKey(pool) => { - self.spo_stake.get(pool).inspect(|ds| votes.pool += ds.live); - } - } - } - } - votes - } - - /// Checks whether `action_id` is expired at the beginning of `new_epoch`. - fn is_expired(&self, new_epoch: u64, action_id: &GovActionId) -> Result { - info!("Checking whether {action_id} is expired at new epoch {new_epoch}"); - let (proposal_epoch, _proposal) = self - .proposals - .get(action_id) - .ok_or_else(|| anyhow!("action {} not found", action_id))?; - - Ok(proposal_epoch + self.get_conway_params()?.gov_action_lifetime as u64 <= new_epoch) - } - - fn pack_as_enact_state_elem(p: &ProposalProcedure) -> Option { - match &p.gov_action { - GovernanceAction::HardForkInitiation(_hf) => None, - GovernanceAction::TreasuryWithdrawals(_wt) => None, - GovernanceAction::Information => None, - - GovernanceAction::ParameterChange(pc) => { - Some(EnactStateElem::Params(pc.protocol_param_update.clone())) - } - GovernanceAction::NewConstitution(nc) => { - Some(EnactStateElem::Constitution(nc.new_constitution.clone())) - } - GovernanceAction::UpdateCommittee(uc) => { - Some(EnactStateElem::Committee(uc.data.clone())) - } - GovernanceAction::NoConfidence(_) => Some(EnactStateElem::NoConfidence), - } - } - - fn retrieve_withdrawal(p: &ProposalProcedure) -> Option { - if let GovernanceAction::TreasuryWithdrawals(ref action) = p.gov_action { - Some(action.clone()) - } else { - None - } - } - - /// Checks and updates action_id state at the start of new_epoch - /// If the action is accepted, returns accepted ProposalProcedure. - fn process_one_proposal( - &mut self, - new_epoch: u64, - voting_state: &VotingRegistrationState, - action_id: &GovActionId, - ) -> Result> { - let outcome = self.is_finally_accepted(voting_state, &action_id)?; - let expired = self.is_expired(new_epoch, &action_id)?; - if outcome.accepted || expired { - self.end_voting(&action_id)?; - info!( - "New epoch {new_epoch}: voting for {action_id} outcome: {}, expired: {expired}", - outcome.accepted - ); - return Ok(Some(outcome)); - } - - Ok(None) - } - - fn finalize_conway_voting( - &mut self, - new_block: &BlockInfo, - voting_state: &VotingRegistrationState, - ) -> Result> { - let mut outcome = Vec::::new(); - let actions = self.proposals.keys().map(|a| a.clone()).collect::>(); - - for action_id in actions.iter() { - info!("Epoch {}: processing action {}", new_block.epoch, action_id); - match self.process_one_proposal(new_block.epoch, &voting_state, &action_id) { - Err(e) => error!("Error processing governance {action_id}: {e}"), - Ok(None) => (), - Ok(Some(out)) if out.accepted => { - let mut action_to_perform = GovernanceOutcomeVariant::NoAction; - - if let Some(elem) = Self::pack_as_enact_state_elem(&out.procedure) { - action_to_perform = GovernanceOutcomeVariant::EnactStateElem(elem); - } else if let Some(wt) = Self::retrieve_withdrawal(&out.procedure) { - action_to_perform = GovernanceOutcomeVariant::TreasuryWithdrawal(wt); - } - - outcome.push(GovernanceOutcome { - voting: out, - action_to_perform, - }) - } - Ok(Some(out)) => outcome.push(GovernanceOutcome { - voting: out, - action_to_perform: GovernanceOutcomeVariant::NoAction, - }), - } - } - - Ok(outcome) - } - fn recalculate_voting_state(&self) -> Result { let drep_stake = self.drep_stake.iter().map(|(_dr, lov)| lov).sum(); - let committee_usize = self.get_conway_params()?.committee.members.len(); + let committee_usize = self.conway_voting.get_conway_params()?.committee.members.len(); let committee = committee_usize.try_into().or_else(|e| { Err(anyhow!( "Commitee size: conversion usize -> u64 failed, {e}" @@ -382,34 +177,42 @@ impl State { if self.current_era >= Era::Conway { let voting_state = self.recalculate_voting_state()?; - let outcome = self.finalize_conway_voting(&new_block, &voting_state)?; - let acc = outcome.iter().filter(|oc| oc.voting.accepted).count(); + let ratified = self.conway_voting.finalize_conway_voting( + &new_block, + &voting_state, + &self.drep_stake, + &self.spo_stake, + )?; + self.conway_voting.update_action_status_with_outcomes(new_block.epoch, &ratified)?; + let acc = ratified.iter().filter(|oc| oc.voting.accepted).count(); info!( "Conway voting, epoch {} ({}): {voting_state}, total {} actions, {acc} accepted", new_block.epoch, new_block.era, - outcome.len() + ratified.len() + ); + + self.conway_voting.log_conway_voting_stats(); + info!( + "Conway voting: new epoch {}, outcomes: {ratified:?}", + new_block.epoch ); - output.conway_outcomes = outcome; + output.conway_outcomes = ratified; } - return Ok(output); + + self.conway_voting.print_outcome_to_verify(&output.conway_outcomes)?; + Ok(output) } - async fn log_stats(&self) { - info!("props: {}, props_with_id: {}, votes: {}, stored proposal procedures: {}, drep stake msgs (size): {} ({})", - self.proposal_count, self.action_proposal_count, self.votes_count, self.proposals.len(), - self.drep_stake_messages_count, self.drep_stake.len(), + fn log_stats(&self) { + info!( + "{}, {}, drep stake msgs (size): {} ({})", + self.alonzo_babbage_voting.get_stats(), + self.conway_voting.get_stats(), + self.drep_stake_messages_count, + self.drep_stake.len(), ); - - for (action_id, procedure) in self.votes.iter() { - info!( - "{}{} => {}", - action_id, - [" (absent)", ""][self.proposals.contains_key(action_id) as usize], - procedure.len() - ) - } } pub async fn send(&self, block: &BlockInfo, message: GovernanceOutcomesMessage) -> Result<()> { @@ -432,12 +235,12 @@ impl State { /// Get list of actual voting proposals pub fn list_proposals(&self) -> Vec { - self.proposals.keys().cloned().collect() + self.conway_voting.proposals.keys().cloned().collect() } /// Get details for a specific proposal pub fn get_proposal(&self, id: &GovActionId) -> Option { - self.proposals.get(id).map(|(_epoch, prop)| prop.clone()) + self.conway_voting.proposals.get(id).map(|(_epoch, prop)| prop.clone()) } /// Get list of votes for a specific proposal @@ -445,7 +248,7 @@ impl State { &self, proposal_id: &GovActionId, ) -> Result> { - match self.votes.get(proposal_id) { + match self.conway_voting.votes.get(proposal_id) { Some(all_votes) => Ok(all_votes.clone()), None => Err(anyhow::anyhow!( "Governance action: {:?} not found", @@ -455,7 +258,7 @@ impl State { } pub async fn tick(&self) -> Result<()> { - self.log_stats().await; + self.log_stats(); Ok(()) } } diff --git a/modules/governance_state/src/voting_state.rs b/modules/governance_state/src/voting_state.rs index eb511243..1619b2f4 100644 --- a/modules/governance_state/src/voting_state.rs +++ b/modules/governance_state/src/voting_state.rs @@ -166,8 +166,9 @@ impl VotingRegistrationState { /// Computes necessary votes count to accept proposal `pp`, according to /// actual parameters. The result is triple of votes' thresholds (as fraction of the - /// total corresponding votes count): (Pool, DRep, Committee) - pub fn get_action_thresholds( + /// total corresponding votes count): (Pool, DRep, Committee). + /// This function computes results in full governance implementation ('plomin' sub-era). + fn get_plomin_action_thresholds( &self, pp: &ProposalProcedure, thresholds: &ConwayParams, @@ -233,4 +234,35 @@ impl VotingRegistrationState { GovernanceAction::Information => self.proportional_count(one, one, zero), } } + + /// Computes necessary votes count to accept proposal `pp`, according to + /// actual parameters. The result is triple of votes' thresholds (as fraction of the + /// total corresponding votes count): (Pool, DRep, Committee). + /// This function variant works both for bootstrap governance era (Chang sub-era), + /// and full governance (Plomin sub-era) --- this is controlled by `bootstrap` parameter. + pub fn get_action_thresholds( + &self, + pp: &ProposalProcedure, + thresholds: &ConwayParams, + bootstrap: bool, + ) -> Result { + // In case of governance bootstrap (Chang sub-era for Conway) Info, ParamChange and + // HardFork actions are allowed, with dreps voting only for Info. + if bootstrap { + match &pp.gov_action { + GovernanceAction::Information => self.get_plomin_action_thresholds(pp, thresholds), + + GovernanceAction::ParameterChange(_) | GovernanceAction::HardForkInitiation(_) => { + let mut votes_count = self.get_plomin_action_thresholds(pp, thresholds)?; + votes_count.drep = 0; + Ok(votes_count) + } + + // All other actions can never be approved + _ => Ok(VotesCount::infinity()), + } + } else { + self.get_plomin_action_thresholds(pp, thresholds) + } + } } diff --git a/modules/parameters_state/src/parameters_updater.rs b/modules/parameters_state/src/parameters_updater.rs index 2854f10d..36244d0b 100644 --- a/modules/parameters_state/src/parameters_updater.rs +++ b/modules/parameters_state/src/parameters_updater.rs @@ -246,13 +246,16 @@ impl ParametersUpdater { .params .conway .as_mut() - .ok_or_else(|| anyhow!("Shelley must present for enact state"))?; + .ok_or_else(|| anyhow!("Conway must present for enact state"))?; match &u { EnactStateElem::Params(pu) => self.update_params(&pu)?, EnactStateElem::Constitution(cu) => c.constitution = cu.clone(), EnactStateElem::Committee(cu) => Self::update_committee(&mut c.committee, cu), EnactStateElem::NoConfidence => c.committee.members.clear(), + EnactStateElem::ProtVer(pv) => { + self.sh_upd(|sp| &mut sp.protocol_version, &Some(pv.clone()))? + } } Ok(()) diff --git a/modules/tx_unpacker/src/map_parameters.rs b/modules/tx_unpacker/src/map_parameters.rs index bffcf83e..d856966b 100644 --- a/modules/tx_unpacker/src/map_parameters.rs +++ b/modules/tx_unpacker/src/map_parameters.rs @@ -643,7 +643,7 @@ fn map_governance_action(action: &conway::GovAction) -> Result conway::GovAction::HardForkInitiation(id, version) => Ok( GovernanceAction::HardForkInitiation(HardForkInitiationAction { previous_action_id: map_nullable_gov_action_id(id)?, - protocol_version: *version, + protocol_version: protocol_params::ProtocolVersion::new(version.0, version.1), }), ), diff --git a/processes/replayer/src/playback.rs b/processes/replayer/src/playback.rs index 6ae07e9f..82521bf0 100644 --- a/processes/replayer/src/playback.rs +++ b/processes/replayer/src/playback.rs @@ -188,7 +188,7 @@ impl PlaybackRunner { info!("Current replay state: {stats}"); } - async fn run(&mut self) -> Result<()> { + async fn run_loop(&mut self) -> Result<()> { // Initializing message status for (topic, prefix, _epoch_bound, _skip_zero) in self.topics.clone().iter() { let msg = self @@ -228,4 +228,17 @@ impl PlaybackRunner { info!("All messages replayed, stopping"); Ok(()) } + + async fn run(&mut self) -> Result<()> { + match self.run_loop().await { + Err(e) => { + tracing::error!("Error running playback: {e}"); + Err(e) + } + Ok(()) => { + info!("Playback is over"); + Ok(()) + } + } + } }