diff --git a/Cargo.lock b/Cargo.lock index 190364851..2739a6d86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -100,16 +100,6 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" -[[package]] -name = "alloy-rlp" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d58d9f5da7b40e9bfff0b7e7816700be4019db97d4b6359fe7f94a9e22e42ac" -dependencies = [ - "arrayvec", - "bytes 1.6.0", -] - [[package]] name = "android-tzdata" version = "0.1.1" @@ -211,130 +201,6 @@ dependencies = [ "password-hash", ] -[[package]] -name = "ark-ff" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" -dependencies = [ - "ark-ff-asm 0.3.0", - "ark-ff-macros 0.3.0", - "ark-serialize 0.3.0", - "ark-std 0.3.0", - "derivative", - "num-bigint", - "num-traits", - "paste", - "rustc_version 0.3.3", - "zeroize", -] - -[[package]] -name = "ark-ff" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" -dependencies = [ - "ark-ff-asm 0.4.2", - "ark-ff-macros 0.4.2", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "derivative", - "digest 0.10.7", - "itertools 0.10.5", - "num-bigint", - "num-traits", - "paste", - "rustc_version 0.4.0", - "zeroize", -] - -[[package]] -name = "ark-ff-asm" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-ff-asm" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-ff-macros" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" -dependencies = [ - "num-bigint", - "num-traits", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-ff-macros" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" -dependencies = [ - "num-bigint", - "num-traits", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-serialize" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" -dependencies = [ - "ark-std 0.3.0", - "digest 0.9.0", -] - -[[package]] -name = "ark-serialize" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" -dependencies = [ - "ark-std 0.4.0", - "digest 0.10.7", - "num-bigint", -] - -[[package]] -name = "ark-std" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" -dependencies = [ - "num-traits", - "rand", -] - -[[package]] -name = "ark-std" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" -dependencies = [ - "num-traits", - "rand", -] - [[package]] name = "arrayref" version = "0.3.7" @@ -811,17 +677,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "auto_impl" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - [[package]] name = "autocfg" version = "1.2.0" @@ -1098,7 +953,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "digest 0.10.7", + "digest", ] [[package]] @@ -1277,7 +1132,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "142316461ed3a3dfcba10417317472da5bfd0461e4d276bf7c07b330766d9490" dependencies = [ "async-std", - "digest 0.10.7", + "digest", "either", "futures 0.3.30", "hex", @@ -1332,7 +1187,7 @@ checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" dependencies = [ "camino", "cargo-platform", - "semver 1.0.22", + "semver", "serde", "serde_json", ] @@ -2174,10 +2029,10 @@ dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", - "digest 0.10.7", + "digest", "fiat-crypto 0.2.7", "platforms", - "rustc_version 0.4.0", + "rustc_version", "subtle", "zeroize", ] @@ -2433,7 +2288,7 @@ dependencies = [ "convert_case 0.4.0", "proc-macro2", "quote", - "rustc_version 0.4.0", + "rustc_version", "syn 1.0.109", ] @@ -2514,15 +2369,6 @@ dependencies = [ "syn 2.0.60", ] -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - [[package]] name = "digest" version = "0.10.7" @@ -2631,7 +2477,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", - "digest 0.10.7", + "digest", "elliptic-curve", "rfc6979", "signature", @@ -2677,7 +2523,7 @@ checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", - "digest 0.10.7", + "digest", "ff", "generic-array", "group", @@ -2846,6 +2692,12 @@ dependencies = [ "str-buf", ] +[[package]] +name = "ethnum" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b90ca2580b73ab6a1f724b76ca11ab632df820fd6040c336200d2c1df7b3c82c" + [[package]] name = "event-listener" version = "2.5.3" @@ -2945,17 +2797,6 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" -[[package]] -name = "fastrlp" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" -dependencies = [ - "arrayvec", - "auto_impl", - "bytes 1.6.0", -] - [[package]] name = "fd-lock" version = "3.0.13" @@ -3612,7 +3453,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.7", + "digest", ] [[package]] @@ -5233,7 +5074,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest 0.10.7", + "digest", ] [[package]] @@ -5433,7 +5274,7 @@ dependencies = [ "config", "console-subscriber", "crossterm 0.25.0", - "digest 0.10.7", + "digest", "futures 0.3.30", "log", "log4rs", @@ -5546,7 +5387,7 @@ dependencies = [ "derivative", "diesel", "diesel_migrations", - "digest 0.10.7", + "digest", "fs2", "futures 0.3.30", "itertools 0.10.5", @@ -6499,7 +6340,7 @@ dependencies = [ "curve25519-dalek", "derive_builder", "des", - "digest 0.10.7", + "digest", "ed25519-dalek", "elliptic-curve", "flate2", @@ -6857,22 +6698,6 @@ dependencies = [ "syn 2.0.60", ] -[[package]] -name = "proptest" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" -dependencies = [ - "bitflags 2.5.0", - "lazy_static", - "num-traits", - "rand", - "rand_chacha", - "rand_xorshift", - "regex-syntax 0.8.3", - "unarray", -] - [[package]] name = "prost" version = "0.9.0" @@ -7237,15 +7062,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_xorshift" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" -dependencies = [ - "rand_core", -] - [[package]] name = "randomx-rs" version = "1.3.0" @@ -7509,7 +7325,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" dependencies = [ - "digest 0.10.7", + "digest", ] [[package]] @@ -7541,16 +7357,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "rlp" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" -dependencies = [ - "bytes 1.6.0", - "rustc-hex", -] - [[package]] name = "ron" version = "0.8.1" @@ -7580,7 +7386,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" dependencies = [ "const-oid", - "digest 0.10.7", + "digest", "num-bigint-dig", "num-integer", "num-traits", @@ -7645,36 +7451,6 @@ dependencies = [ "webrtc-util", ] -[[package]] -name = "ruint" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f308135fef9fc398342da5472ce7c484529df23743fb7c734e0f3d472971e62" -dependencies = [ - "alloy-rlp", - "ark-ff 0.3.0", - "ark-ff 0.4.2", - "bytes 1.6.0", - "fastrlp", - "num-bigint", - "num-traits", - "parity-scale-codec", - "primitive-types", - "proptest", - "rand", - "rlp", - "ruint-macro", - "serde", - "valuable", - "zeroize", -] - -[[package]] -name = "ruint-macro" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f86854cf50259291520509879a5c294c3c9a4c334e9ff65071c51e42ef1e2343" - [[package]] name = "rust-ini" version = "0.19.0" @@ -7703,22 +7479,13 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" -[[package]] -name = "rustc_version" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" -dependencies = [ - "semver 0.11.0", -] - [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.22", + "semver", ] [[package]] @@ -7987,15 +7754,6 @@ dependencies = [ "libc", ] -[[package]] -name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] - [[package]] name = "semver" version = "1.0.22" @@ -8005,15 +7763,6 @@ dependencies = [ "serde", ] -[[package]] -name = "semver-parser" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] - [[package]] name = "serde" version = "1.0.197" @@ -8165,7 +7914,7 @@ checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.7", + "digest", ] [[package]] @@ -8182,7 +7931,7 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.7", + "digest", ] [[package]] @@ -8193,7 +7942,7 @@ checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.7", + "digest", ] [[package]] @@ -8202,7 +7951,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest 0.10.7", + "digest", "keccak", ] @@ -8258,7 +8007,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest 0.10.7", + "digest", "rand_core", ] @@ -8399,7 +8148,7 @@ dependencies = [ "curve25519-dalek", "rand_core", "ring 0.17.8", - "rustc_version 0.4.0", + "rustc_version", "sha2", "subtle", ] @@ -8465,7 +8214,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da7a2b3c2bc9693bcb40870c4e9b5bf0d79f9cb46273321bf855ec513e919082" dependencies = [ "base64 0.21.7", - "digest 0.10.7", + "digest", "hex", "miette", "serde", @@ -8777,7 +8526,7 @@ dependencies = [ "fiat-crypto 0.1.20", "platforms", "rand_core", - "rustc_version 0.4.0", + "rustc_version", "serde", "subtle", "zeroize", @@ -8831,7 +8580,7 @@ dependencies = [ "byteorder", "derivative", "derive_more", - "digest 0.10.7", + "digest", "itertools 0.6.5", "lazy_static", "merlin", @@ -8893,7 +8642,7 @@ dependencies = [ "blake2", "borsh", "chacha20poly1305", - "digest 0.10.7", + "digest", "newtype-ops", "once_cell", "primitive-types", @@ -8921,7 +8670,7 @@ dependencies = [ "cidr", "data-encoding", "derivative", - "digest 0.10.7", + "digest", "futures 0.3.30", "lmdb-zero", "log", @@ -8964,7 +8713,7 @@ dependencies = [ "chrono", "diesel", "diesel_migrations", - "digest 0.10.7", + "digest", "futures 0.3.30", "log", "log-mdc", @@ -9067,7 +8816,7 @@ dependencies = [ "chrono", "decimal-rs", "derivative", - "digest 0.10.7", + "digest", "fs2", "futures 0.3.30", "hex", @@ -9125,7 +8874,7 @@ checksum = "63a3ed2c551101eb42b7f9386c207e28d53e6816f7b4c9a0883548922f317b3e" dependencies = [ "blake2", "borsh", - "digest 0.10.7", + "digest", "log", "once_cell", "rand_chacha", @@ -9193,12 +8942,13 @@ name = "tari_dan_common_types" version = "0.6.0" dependencies = [ "blake2", + "ethnum", + "indexmap 2.2.6", "libp2p-identity", "newtype-ops", "prost 0.12.4", "prost-types 0.9.0", "rand", - "ruint", "serde", "tari_bor", "tari_common", @@ -9223,7 +8973,7 @@ dependencies = [ "indexmap 2.2.6", "log", "rand", - "semver 1.0.22", + "semver", "serde", "serde_json", "tari_bor", @@ -9355,7 +9105,7 @@ version = "0.6.0" dependencies = [ "blake2", "chacha20poly1305", - "digest 0.10.7", + "digest", "rand", "tari_crypto", "tari_engine_types", @@ -9423,7 +9173,7 @@ dependencies = [ "async-trait", "blake2", "chrono", - "digest 0.10.7", + "digest", "jsonwebtoken", "log", "serde", @@ -9476,7 +9226,7 @@ version = "0.6.0" dependencies = [ "base64 0.21.7", "blake2", - "digest 0.10.7", + "digest", "hex", "lazy_static", "rand", @@ -9541,7 +9291,7 @@ version = "1.0.0-dan.11" source = "git+https://github.com/tari-project/tari.git?branch=feature-dan2#7d480c50513e93c70566b4c2ce91a7afee006f05" dependencies = [ "borsh", - "digest 0.10.7", + "digest", "tari_crypto", ] @@ -9652,7 +9402,7 @@ dependencies = [ "derivative", "diesel", "diesel_migrations", - "digest 0.10.7", + "digest", "futures 0.3.30", "log", "rand", @@ -9702,7 +9452,7 @@ version = "1.0.0-dan.11" source = "git+https://github.com/tari-project/tari.git?branch=feature-dan2#7d480c50513e93c70566b4c2ce91a7afee006f05" dependencies = [ "borsh", - "digest 0.10.7", + "digest", "log", "serde", "tari_common", @@ -9742,7 +9492,7 @@ dependencies = [ "rand", "reqwest", "rustls 0.20.9", - "semver 1.0.22", + "semver", "serde", "tari_common", "tari_comms", @@ -9836,7 +9586,7 @@ source = "git+https://github.com/tari-project/tari.git?branch=feature-dan2#7d480 dependencies = [ "blake2", "borsh", - "digest 0.10.7", + "digest", "integer-encoding", "serde", "sha2", @@ -11087,12 +10837,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "unarray" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" - [[package]] name = "unicase" version = "2.7.0" diff --git a/Cargo.toml b/Cargo.toml index a482c63bd..bd820e701 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -167,6 +167,7 @@ diesel_migrations = "2" digest = "0.10" dirs = "4.0.0" env_logger = "0.10.0" +ethnum = "1.5.0" fern = "0.6.2" futures = "0.3.30" futures-bounded = "0.2.3" @@ -212,7 +213,6 @@ quote = "1.0.7" rand = "0.8.5" rayon = "1.7.0" reqwest = "0.11.16" -ruint = "1.8.0" semver = "1.0" serde = { version = "1.0", default-features = false } serde_json = "1.0" diff --git a/applications/tari_indexer/src/bootstrap.rs b/applications/tari_indexer/src/bootstrap.rs index 5153f223e..d067ee915 100644 --- a/applications/tari_indexer/src/bootstrap.rs +++ b/applications/tari_indexer/src/bootstrap.rs @@ -22,6 +22,7 @@ use std::{fs, io, str::FromStr}; +use anyhow::Context; use libp2p::identity; use minotari_app_utilities::identity_management; use tari_base_node_client::grpc::GrpcBaseNodeClient; @@ -117,7 +118,10 @@ pub async fn spawn_services( let (epoch_manager, _) = tari_epoch_manager::base_layer::spawn_service( EpochManagerConfig { base_layer_confirmations: consensus_constants.base_layer_confirmations, - committee_size: consensus_constants.committee_size, + committee_size: consensus_constants + .committee_size + .try_into() + .context("committee_size must be non-zero")?, validator_node_sidechain_id: config.indexer.sidechain_id.clone(), }, global_db.clone(), diff --git a/applications/tari_validator_node/src/bootstrap.rs b/applications/tari_validator_node/src/bootstrap.rs index de91c015c..ba18538dd 100644 --- a/applications/tari_validator_node/src/bootstrap.rs +++ b/applications/tari_validator_node/src/bootstrap.rs @@ -22,7 +22,7 @@ use std::{fs, io, ops::DerefMut, str::FromStr}; -use anyhow::anyhow; +use anyhow::{anyhow, Context}; use futures::{future, FutureExt}; use libp2p::identity; use log::info; @@ -192,7 +192,10 @@ pub async fn spawn_services( // which depends on epoch_manager, so would be a circular dependency. EpochManagerConfig { base_layer_confirmations: consensus_constants.base_layer_confirmations, - committee_size: consensus_constants.committee_size, + committee_size: consensus_constants + .committee_size + .try_into() + .context("committee size must be non-zero")?, validator_node_sidechain_id: config.validator_node.validator_node_sidechain_id.clone(), }, global_db.clone(), diff --git a/dan_layer/common_types/Cargo.toml b/dan_layer/common_types/Cargo.toml index 14da1596c..efb0c5bbe 100644 --- a/dan_layer/common_types/Cargo.toml +++ b/dan_layer/common_types/Cargo.toml @@ -23,14 +23,17 @@ libp2p-identity = { workspace = true, features = [ ] } blake2 = { workspace = true } +ethnum = { workspace = true } newtype-ops = { workspace = true } rand = { workspace = true } prost = { workspace = true } prost-types = { workspace = true } serde = { workspace = true, default-features = true } -ruint = { workspace = true } ts-rs = { workspace = true, optional = true } +[dev-dependencies] +indexmap = { workspace = true } + [package.metadata.cargo-machete] ignored = ["prost", "prost-types"] # false positive, used in OUT_DIR structs diff --git a/dan_layer/common_types/src/shard.rs b/dan_layer/common_types/src/shard.rs index 3dde3c0df..5cae5b1ad 100644 --- a/dan_layer/common_types/src/shard.rs +++ b/dan_layer/common_types/src/shard.rs @@ -7,10 +7,7 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "ts")] use ts_rs::TS; -use crate::{ - uint::{U256, U256_ONE}, - SubstateAddress, -}; +use crate::{uint::U256, SubstateAddress}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[serde(transparent)] @@ -22,21 +19,69 @@ impl Shard { self.0 } - pub fn to_substate_address_range(self, num_committees: u32) -> RangeInclusive { - if num_committees == 0 { - return RangeInclusive::new(SubstateAddress::zero(), SubstateAddress::from_u256(U256::MAX)); + pub fn to_substate_address_range(self, num_shards: u32) -> RangeInclusive { + if num_shards <= 1 { + return RangeInclusive::new(SubstateAddress::zero(), SubstateAddress::max()); } - let bucket = U256::from(self.0); - let num_committees = U256::from(num_committees); - let bucket_size = U256::MAX / num_committees; - let bucket_remainder = U256::MAX % num_committees; - let next_bucket = bucket + U256_ONE; - let start = bucket_size * bucket + bucket_remainder.min(bucket); - let mut end = start + bucket_size; - if next_bucket != num_committees && bucket_remainder <= bucket { - end -= U256_ONE; + + // There will never be close to 2^31-1 committees but the calculation below will overflow/panic if + // num_shards.leading_zeros() == 0. + let num_shards = num_shards.min(crate::substate_address::MAX_NUM_SHARDS); + + let shard_u256 = U256::from(self.0); + + if num_shards.is_power_of_two() { + let shard_size = U256::MAX >> num_shards.trailing_zeros(); + if self.0 == 0 { + return RangeInclusive::new(SubstateAddress::zero(), SubstateAddress::from_u256(shard_size)); + } + + // Add one to each start to account for remainder + let start = shard_u256 * shard_size; + + if self.0 == num_shards - 1 { + return RangeInclusive::new(SubstateAddress::from_u256(start + shard_u256), SubstateAddress::max()); + } + + let next_shard = shard_u256 + 1; + let end = next_shard * shard_size; + return RangeInclusive::new( + SubstateAddress::from_u256(start + shard_u256), + SubstateAddress::from_u256(end + shard_u256), + ); + } + + let num_shards_next_pow2 = num_shards.next_power_of_two(); + // Half the next power of two i.e. num_shards rounded down to previous power of two + let num_shards_prev_pow2 = num_shards_next_pow2 >> 1; + let num_shards_next_pow2 = U256::from(num_shards_next_pow2); + // Power of two division using bit shifts + let half_shard_size = U256::MAX >> num_shards_next_pow2.trailing_zeros(); + + if self.0 == 0 { + return RangeInclusive::new(SubstateAddress::zero(), SubstateAddress::from_u256(half_shard_size)); + } + + // Calculate size of shard at previous power of two + let full_shard_size = U256::MAX >> num_shards_prev_pow2.trailing_zeros(); + // The "extra" half shards in the space + let num_half_shards = num_shards % num_shards_prev_pow2; + + let start = U256::from(self.0.min(num_half_shards * 2)) * half_shard_size + + U256::from(self.0.saturating_sub(num_half_shards * 2)) * full_shard_size; + + if self.0 == num_shards - 1 { + return RangeInclusive::new(SubstateAddress::from_u256(start + shard_u256), SubstateAddress::max()); } - RangeInclusive::new(SubstateAddress::from_u256(start), SubstateAddress::from_u256(end)) + + let next_shard = self.0 + 1; + let end = U256::from(next_shard.min(num_half_shards * 2)) * half_shard_size + + U256::from(next_shard.saturating_sub(num_half_shards * 2)) * full_shard_size; + + RangeInclusive::new( + SubstateAddress::from_u256(start + shard_u256), + SubstateAddress::from_u256(end + shard_u256), + ) } } @@ -65,33 +110,77 @@ impl Display for Shard { #[cfg(test)] mod test { - use crate::uint::{U256, U256_ONE}; + use std::iter; + + use indexmap::IndexMap; + + use super::*; #[test] fn committee_is_properly_computed() { - for num_of_committees in 1..100 { - let mut previous_end = U256::ZERO; - let mut min_committee_size = U256::MAX; - let mut max_committee_size = U256::ZERO; - for bucket_index in 0..num_of_committees { - let bucket = super::Shard::from(bucket_index); - let range = bucket.to_substate_address_range(num_of_committees); - if bucket_index > 0 { + // TODO: clean this up a bit, I wrote this very hastily + let power_of_twos = iter::successors(Some(1), |x| Some(x * 2)).take(10); + let mut split_map = IndexMap::<_, Vec<_>>::new(); + for num_of_shards in power_of_twos { + let mut last_end = U256::ZERO; + for shard_index in 0..num_of_shards { + let shard = Shard::from(shard_index); + let range = shard.to_substate_address_range(num_of_shards); + if shard_index == 0 { + assert_eq!(range.start().to_u256(), U256::ZERO, "First shard should start at 0"); + } else { assert_eq!( range.start().to_u256(), - previous_end + U256_ONE, - "Bucket should start where the previous one ended+1" + last_end + 1, + "Shard should start where the previous one ended+1" ); } - min_committee_size = min_committee_size.min(range.end().to_u256() - range.start().to_u256()); - max_committee_size = max_committee_size.max(range.end().to_u256() - range.start().to_u256()); - previous_end = range.end().to_u256(); + last_end = range.end().to_u256(); + split_map.entry(num_of_shards).or_default().push(range); } - assert!( - num_of_committees <= 1 || max_committee_size <= min_committee_size + U256_ONE, - "Committee sizes should be balanced {min_committee_size} {max_committee_size}" - ); - assert_eq!(previous_end, U256::MAX, "Last bucket should end at U256::MAX"); + assert_eq!(last_end, U256::MAX, "Last shard should end at U256::MAX"); } + + let mut i = 0usize; + for (num_of_shards, splits) in &split_map { + // Each split in the next num_of_shards should match the previous shard splits + let Some(next_splits) = split_map.get(&(num_of_shards << 1)) else { + break; + }; + + i += 1; + + for (split, next_split) in splits.iter().zip( + next_splits + .iter() + .enumerate() + // Every 2nd boundary matches + .filter(|(i, _)| i % 2 == 1) + .map(|(_, s)| s), + ) { + assert_eq!( + split.end().to_u256(), + next_split.end().to_u256(), + "Bucket should end where the next one starts-1" + ); + } + + if splits.len() >= 2 { + let mut size = None; + for split in splits.iter().skip(1).take(splits.len() - 2) { + if let Some(size) = size { + assert_eq!( + split.end().to_u256() - split.start().to_u256(), + size, + "Shard size should be consistent" + ); + } + size = Some(split.end().to_u256() - split.start().to_u256()); + } + } + } + + // Check that we didnt break early + assert_eq!(i, 9); } } diff --git a/dan_layer/common_types/src/substate_address.rs b/dan_layer/common_types/src/substate_address.rs index e21b23c6e..1a71e0b3b 100644 --- a/dan_layer/common_types/src/substate_address.rs +++ b/dan_layer/common_types/src/substate_address.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: BSD-3-Clause use std::{ + cmp, cmp::Ordering, fmt, fmt::{Display, Formatter}, @@ -21,7 +22,15 @@ use tari_engine_types::{ }; use tari_template_lib::{models::ObjectKey, Hash}; -use crate::{shard::Shard, uint::U256}; +use crate::{ + shard::Shard, + uint::{U256, U256_ZERO}, +}; + +/// This is u16::MAX / 2 as a u32 = 32767 shards. Any number of shards greater than this will be clamped to this value. +/// This is done to limit the number of addresses that are added to the final shard to allow the same shard boundaries. +/// TODO: Change num_shards to a u16 +pub(super) const MAX_NUM_SHARDS: u32 = 0x0000_0000_0000_ffff >> 1; #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] #[cfg_attr( @@ -32,7 +41,7 @@ use crate::{shard::Shard, uint::U256}; pub struct SubstateAddress( #[serde(with = "serde_with::hex")] #[cfg_attr(feature = "ts", ts(type = "string"))] - pub [u8; 32], + [u8; 32], ); impl SubstateAddress { @@ -91,7 +100,7 @@ impl SubstateAddress { Self(new_addr.into_array()) } - pub fn new(id: [u8; 32]) -> Self { + pub const fn new(id: [u8; 32]) -> Self { Self(id) } @@ -101,13 +110,17 @@ impl SubstateAddress { pub fn from_bytes(bytes: &[u8]) -> Result { let hash = FixedHash::try_from(bytes)?; - Ok(Self::new(hash.into_array())) + Ok(Self(hash.into_array())) } - pub fn into_array(self) -> [u8; 32] { + pub const fn into_array(self) -> [u8; 32] { self.0 } + pub const fn array(&self) -> &[u8; 32] { + &self.0 + } + pub const fn zero() -> Self { Self([0u8; 32]) } @@ -125,24 +138,72 @@ impl SubstateAddress { } /// Calculates and returns the shard number that this SubstateAddress belongs. - /// A shard is an equal division of the 256-bit shard space. - pub fn to_committee_shard(&self, num_committees: u32) -> Shard { - if num_committees == 0 { + /// A shard is a division of the 256-bit shard space where the boundary of the division if always a power of two. + pub fn to_committee_shard(&self, num_shards: u32) -> Shard { + if num_shards == 0 { + return Shard::from(0u32); + } + let addr_u256 = self.to_u256(); + if addr_u256 == U256_ZERO { + return Shard::from(0u32); + } + if num_shards == 1 { return Shard::from(0u32); } - let shard_size = U256::MAX / U256::from(num_committees); - // 4,294,967,295 committees. - std::cmp::min( - u32::try_from(self.to_u256() / shard_size) - .expect("to_committee_shard: num_committees is a u32, so this cannot fail"), - num_committees - 1, - ) - .into() + + if num_shards.is_power_of_two() { + let shard_size = U256::MAX >> num_shards.trailing_zeros(); + let mut shard = Shard::from( + u32::try_from(addr_u256 / shard_size) + .expect("to_committee_shard: num_shards is a u32, so this cannot fail") + .min(num_shards - 1), + ); + // On boundary + if addr_u256 % shard_size == 0 { + shard = shard.as_u32().saturating_sub(1).into(); + } + return shard; + } + + // 2^15-1 shards with 40 vns per shard = 1,310,680 validators. This limit exists to prevent next_power_of_two + // from panicking. + let num_shards = num_shards.min(MAX_NUM_SHARDS); + + // Round down to the next power of two. + let next_shards_pow_two = num_shards.next_power_of_two(); + let half_shard_size = U256::MAX >> next_shards_pow_two.trailing_zeros(); + let mut next_pow_2_shard = u32::try_from(addr_u256 / half_shard_size) + .expect("to_committee_shard: num_shards is a u32, so this cannot fail"); + + // On boundary + if addr_u256 % half_shard_size == 0 { + next_pow_2_shard = next_pow_2_shard.saturating_sub(1); + } + + // Half the next power of two i.e. num_shards rounded down to previous power of two + let num_shards_pow_two = next_shards_pow_two >> 1; + // The "extra" half shards in the space + let num_half_shards = num_shards % num_shards_pow_two; + + // Shard that we would be in if num_shards was a power of two + let shard = next_pow_2_shard / 2; + + // If the shard is higher than all half shards, + let shard = if shard >= num_half_shards { + // then add those half shards in + shard + num_half_shards + } else { + // otherwise, we use the shard number we'd be in if num_shards was the next power of two + next_pow_2_shard + }; + + // u256::MAX address needs to be clamped to the last shard index + cmp::min(shard, num_shards - 1).into() } - pub fn to_committee_range(&self, num_committees: u32) -> RangeInclusive { - let shard = self.to_committee_shard(num_committees); - shard.to_substate_address_range(num_committees) + pub fn to_address_range(&self, num_shards: u32) -> RangeInclusive { + let shard = self.to_committee_shard(num_shards); + shard.to_substate_address_range(num_shards) } } @@ -210,6 +271,11 @@ impl FromStr for SubstateAddress { #[cfg(test)] mod tests { + use std::{ + iter, + ops::{Bound, RangeBounds}, + }; + use rand::{rngs::OsRng, RngCore}; use super::*; @@ -223,33 +289,228 @@ mod tests { assert_eq!(result, s); } + #[test] + fn to_committee_shard_and_shard_range_match() { + let address = address_at(1, 8); + let shard = address.to_committee_shard(6); + assert_eq!(shard, 1); + + let range = Shard::from(0).to_substate_address_range(2); + assert_range(range, SubstateAddress::zero()..address_at(1, 2)); + let range = shard.to_substate_address_range(2); + assert_range(range, address_at(1, 2)..=SubstateAddress::max()); + let range = shard.to_substate_address_range(6); + assert_range(range, address_at(1, 8)..address_at(2, 8)); + } + #[test] fn shard_range() { - let range = divide_floor(SubstateAddress::max(), 2).to_committee_range(3); - assert_eq!(range, shard(1, 3)..=minus_one(shard(2, 3))); + let range = SubstateAddress::zero().to_address_range(2); + assert_range(range, SubstateAddress::zero()..address_at(1, 2)); + let range = SubstateAddress::max().to_address_range(2); + assert_range(range, address_at(1, 2)..=SubstateAddress::max()); + + // num_shards is a power of two + let power_of_twos = + iter::successors(Some(MAX_NUM_SHARDS.next_power_of_two() >> 1), |&x| Some(x >> 1)).take(15 - 2); + for power_of_two in power_of_twos { + for i in 0..power_of_two { + let range = address_at(i, power_of_two).to_address_range(power_of_two); + if i == 0 { + assert_range(range, SubstateAddress::zero()..address_at(1, power_of_two)); + } else if i >= power_of_two - 1 { + assert_range(range, address_at(i, power_of_two)..=SubstateAddress::max()); + } else { + assert_range(range, address_at(i, power_of_two)..address_at(i + 1, power_of_two)); + } + } + } + + // Half shards + let range = address_at(0, 8).to_address_range(6); + assert_range(range, SubstateAddress::zero()..address_at(1, 8)); + let range = address_at(1, 8).to_address_range(6); + assert_range(range, address_at(1, 8)..address_at(2, 8)); + let range = address_at(2, 8).to_address_range(6); + assert_range(range, address_at(2, 8)..address_at(3, 8)); + let range = address_at(3, 8).to_address_range(6); + assert_range(range, address_at(3, 8)..address_at(4, 8)); + // Whole shards + let range = address_at(4, 8).to_address_range(6); + assert_range(range, address_at(4, 8)..address_at(6, 8)); + let range = address_at(5, 8).to_address_range(6); + assert_range(range, address_at(4, 8)..address_at(6, 8)); + let range = address_at(6, 8).to_address_range(6); + assert_range(range, address_at(6, 8)..=SubstateAddress::max()); + let range = address_at(7, 8).to_address_range(6); + assert_range(range, address_at(6, 8)..=SubstateAddress::max()); + let range = address_at(8, 8).to_address_range(6); + assert_range(range, address_at(6, 8)..=SubstateAddress::max()); + + let range = plus_one(address_at(1, 4)).to_address_range(20); + // The half shards will split at intervals of END_SHARD_MAX / 32 + assert_range(range, address_at(8, 32)..address_at(10, 32)); + + let range = plus_one(divide_floor(SubstateAddress::max(), 2)).to_address_range(10); + assert_range(range, address_at(8, 16)..address_at(10, 16)); + + let range = address_at(42, 256).to_address_range(256); + assert_range(range, address_at(42, 256)..address_at(43, 256)); + let range = address_at(128, 256).to_address_range(256); + assert_range(range, address_at(128, 256)..address_at(129, 256)); } #[test] - fn shards() { + fn to_committee_shard() { + // Edge cases let shard = SubstateAddress::max().to_committee_shard(0); assert_eq!(shard, 0); - let shard = divide_floor(SubstateAddress::max(), 5).to_committee_shard(20); + let shard = SubstateAddress::zero().to_committee_shard(0); + assert_eq!(shard, 0); + let shard = SubstateAddress::max().to_committee_shard(u32::MAX); + assert_eq!(shard, u32::from(u16::MAX >> 1) - 1); + + let shard = SubstateAddress::zero().to_committee_shard(2); + assert_eq!(shard, 0); + let shard = address_at(1, 2).to_committee_shard(2); + assert_eq!(shard, 1); + let shard = plus_one(address_at(1, 2)).to_committee_shard(2); + assert_eq!(shard, 1); + let shard = SubstateAddress::max().to_committee_shard(2); + assert_eq!(shard, 1); + + for i in 0..=32 { + let shard = divide_shard_space(i, 32).to_committee_shard(1); + assert_eq!(shard, 0); + } + + // 2 shards, exactly half of the physical shard space + for i in 0..=8 { + let shard = divide_shard_space(i, 16).to_committee_shard(2); + assert_eq!(shard, 0, "{shard} is not 0 for i: {i}"); + } + + for i in 9..16 { + let shard = divide_shard_space(i, 16).to_committee_shard(2); + assert_eq!(shard, 1, "{shard} is not 1 for i: {i}"); + } + + // If the number of shards is a power of two, then to_committee_shard should always return the equally divided + // shard number. We test this for the first u16::MAX power of twos. + // At boundary + for power_of_two in iter::successors(Some(1), |&x| Some(x * 2)).take(16) { + for i in 1..power_of_two { + let shard = divide_shard_space(i, power_of_two).to_committee_shard(power_of_two); + assert_eq!( + shard, + i - 1, + "Got: {shard}, Expected: {i} for power_of_two: {power_of_two}" + ); + } + } + // +1 boundary + for power_of_two in iter::successors(Some(1), |&x| Some(x * 2)).take(16) { + for i in 0..power_of_two { + let shard = plus_one(address_at(i, power_of_two)).to_committee_shard(power_of_two); + assert_eq!(shard, i, "Got: {shard}, Expected: {i} for power_of_two: {power_of_two}"); + } + } + + let shard = address_at(0, 8).to_committee_shard(6); + assert_eq!(shard, 0); + let shard = minus_one(address_at(1, 8)).to_committee_shard(6); + assert_eq!(shard, 0); + let shard = address_at(1, 8).to_committee_shard(6); + assert_eq!(shard, 1); + let shard = address_at(2, 8).to_committee_shard(6); + assert_eq!(shard, 2); + let shard = plus_one(address_at(1, 8)).to_committee_shard(6); + assert_eq!(shard, 1); + + let shard = plus_one(address_at(0, 8)).to_committee_shard(6); + assert_eq!(shard, 0); + let shard = plus_one(address_at(1, 8)).to_committee_shard(6); + assert_eq!(shard, 1); + let shard = plus_one(address_at(2, 8)).to_committee_shard(6); + assert_eq!(shard, 2); + let shard = plus_one(address_at(3, 8)).to_committee_shard(6); + assert_eq!(shard, 3); + let shard = plus_one(address_at(4, 8)).to_committee_shard(6); assert_eq!(shard, 4); - let shard = divide_floor(SubstateAddress::max(), 2).to_committee_shard(10); + let shard = plus_one(address_at(5, 8)).to_committee_shard(6); + assert_eq!(shard, 4); + let shard = plus_one(address_at(6, 8)).to_committee_shard(6); + assert_eq!(shard, 5); + let shard = plus_one(address_at(7, 8)).to_committee_shard(6); + assert_eq!(shard, 5); + let shard = minus_one(address_at(8, 8)).to_committee_shard(6); + assert_eq!(shard, 5); + let shard = SubstateAddress::max().to_committee_shard(6); assert_eq!(shard, 5); + + let shard = plus_one(address_at(0, 8)).to_committee_shard(5); + assert_eq!(shard, 0); + let shard = plus_one(address_at(1, 8)).to_committee_shard(5); + assert_eq!(shard, 1); + let shard = plus_one(address_at(2, 8)).to_committee_shard(5); + assert_eq!(shard, 2); + let shard = plus_one(address_at(3, 8)).to_committee_shard(5); + assert_eq!(shard, 2); + let shard = plus_one(address_at(4, 8)).to_committee_shard(5); + assert_eq!(shard, 3); + let shard = plus_one(address_at(5, 8)).to_committee_shard(5); + assert_eq!(shard, 3); + let shard = plus_one(address_at(6, 8)).to_committee_shard(5); + assert_eq!(shard, 4); + let shard = plus_one(address_at(7, 8)).to_committee_shard(5); + assert_eq!(shard, 4); + let shard = minus_one(address_at(8, 8)).to_committee_shard(5); + assert_eq!(shard, 4); + let shard = SubstateAddress::max().to_committee_shard(5); + assert_eq!(shard, 4); + + let shard = plus_one(address_at(1, 4)).to_committee_shard(20); + // 1/4 * 20 = 5 + 4 half shards in the start of the shard space, - 1 for index + assert_eq!(shard, 5 + 4 - 1); + let shard = divide_floor(SubstateAddress::max(), 2).to_committee_shard(10); + // 8 / 2 = 4 + 2 half shards in the start of the shard space, +1 on boundary, - 1 for index + assert_eq!(shard, 4 + 2 + 1 - 1); let shard = divide_floor(SubstateAddress::max(), 2).to_committee_shard(256); assert_eq!(shard, 128); } - #[test] - fn max_committees() { - let shard = SubstateAddress::max().to_committee_shard(u32::MAX); - // When we have n committees, the last committee is n-1. - assert_eq!(shard, u32::MAX - 1); + /// Returns the address of the floor division of the shard space + fn divide_shard_space(part: u32, of: u32) -> SubstateAddress { + assert!(part <= of); + if part == 0 { + return SubstateAddress::zero(); + } + if part == of { + return SubstateAddress::max(); + } + let size = U256::MAX / U256::from(of); + SubstateAddress::from_u256(U256::from(part) * size) } - fn shard(shard: u32, of: u32) -> SubstateAddress { - SubstateAddress::from_u256(U256::from(shard) * (U256::MAX / U256::from(of))) + /// Returns the start address of the shard with given num_shards + fn address_at(shard: u32, num_shards: u32) -> SubstateAddress { + // + shard: For each shard we add 1 to account for remainder + add(divide_shard_space(shard, num_shards), shard) + // SubstateAddress::from_u256( + // divide_shard_space(shard, num_shards) + // .to_u256() + // .saturating_add(U256::from(shard)), + // ) + // assert!(shard <= of); + // if shard == 0 { + // return SubstateAddress::zero(); + // } + // if shard == of { + // return SubstateAddress::max(); + // } + // let size = U256::MAX / U256::from(of); + // let shard = U256::from(shard); + // SubstateAddress::from_u256(shard * size + shard) } fn divide_floor(shard: SubstateAddress, by: u32) -> SubstateAddress { @@ -259,4 +520,41 @@ mod tests { fn minus_one(shard: SubstateAddress) -> SubstateAddress { SubstateAddress::from_u256(shard.to_u256() - U256::from(1u32)) } + + fn plus_one(address: SubstateAddress) -> SubstateAddress { + add(address, 1) + } + + fn add(shard: SubstateAddress, v: u32) -> SubstateAddress { + SubstateAddress::from_u256(shard.to_u256().saturating_add(U256::from(v))) + } + + fn assert_range>(range: RangeInclusive, expected: R) { + let start = match expected.start_bound() { + Bound::Included(&start) => start, + Bound::Excluded(&start) => minus_one(start), + Bound::Unbounded => panic!("Expected start bound"), + }; + + let end = match expected.end_bound() { + Bound::Included(&end) => end, + Bound::Excluded(&end) => minus_one(end), + Bound::Unbounded => panic!("Expected end bound"), + }; + + assert_eq!( + range.start().to_u256(), + start.to_u256(), + "Start range: Got {} != expected {}", + range.start(), + start + ); + assert_eq!( + range.end().to_u256(), + end.to_u256(), + "End range: Got {} != expected {}", + range.end(), + end, + ); + } } diff --git a/dan_layer/common_types/src/uint.rs b/dan_layer/common_types/src/uint.rs index 50a1f5873..0ecd8c841 100644 --- a/dan_layer/common_types/src/uint.rs +++ b/dan_layer/common_types/src/uint.rs @@ -1,9 +1,10 @@ // Copyright 2023 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -pub type U256 = ruint::Uint<256, 4>; +pub type U256 = ethnum::U256; -pub const U256_ONE: U256 = U256::from_limbs([1, 0, 0, 0]); +pub const U256_ZERO: U256 = U256::from_words(0, 0); +pub const U256_ONE: U256 = U256::from_words(0, 1); #[cfg(test)] mod tests { diff --git a/dan_layer/common_types/src/validator_metadata.rs b/dan_layer/common_types/src/validator_metadata.rs index 1ef8d1392..cbaa2e7f1 100644 --- a/dan_layer/common_types/src/validator_metadata.rs +++ b/dan_layer/common_types/src/validator_metadata.rs @@ -29,7 +29,7 @@ impl ValidatorMetadata { pub fn vn_node_hash(network: Network, public_key: &PublicKey, substate_address: &SubstateAddress) -> FixedHash { TariBaseLayerHasher32::::new_with_label(&format!("validator_nodes.n{}", network.as_byte())) .chain(public_key) - .chain(&substate_address.0) + .chain(substate_address.array()) .finalize() .into() } diff --git a/dan_layer/consensus_tests/src/support/epoch_manager.rs b/dan_layer/consensus_tests/src/support/epoch_manager.rs index e5e5085d8..c04afbdd5 100644 --- a/dan_layer/consensus_tests/src/support/epoch_manager.rs +++ b/dan_layer/consensus_tests/src/support/epoch_manager.rs @@ -18,7 +18,7 @@ use tari_dan_storage::global::models::ValidatorNode; use tari_epoch_manager::{EpochManagerError, EpochManagerEvent, EpochManagerReader}; use tokio::sync::{broadcast, Mutex, MutexGuard}; -use crate::support::{address::TestAddress, helpers::random_substate_in_bucket}; +use crate::support::{address::TestAddress, helpers::random_substate_in_shard}; #[derive(Debug, Clone)] pub struct TestEpochManager { @@ -87,7 +87,7 @@ impl TestEpochManager { let num_committees = committees.len() as u32; for (shard, committee) in committees { for (address, pk) in &committee.members { - let substate_address = random_substate_in_bucket(shard, num_committees); + let substate_address = random_substate_in_shard(shard, num_committees); state.validator_shards.insert( address.clone(), ( diff --git a/dan_layer/consensus_tests/src/support/helpers.rs b/dan_layer/consensus_tests/src/support/helpers.rs index e83d1fbe5..6f0b9bc59 100644 --- a/dan_layer/consensus_tests/src/support/helpers.rs +++ b/dan_layer/consensus_tests/src/support/helpers.rs @@ -2,16 +2,16 @@ // SPDX-License-Identifier: BSD-3-Clause use rand::{rngs::OsRng, Rng}; -use tari_dan_common_types::{shard::Shard, uint::U256}; +use tari_dan_common_types::shard::Shard; use tari_engine_types::substate::SubstateId; use tari_template_lib::models::{ComponentAddress, ComponentKey, EntityId, ObjectKey}; use tari_transaction::VersionedSubstateId; -pub(crate) fn random_substate_in_bucket(bucket: Shard, num_committees: u32) -> VersionedSubstateId { - let shard_size = U256::MAX / U256::from(num_committees); - let offset = u128::from_le_bytes(copy_fixed(&shard_size.as_le_bytes()[..16])); - let shard = shard_size * U256::from(bucket.as_u32()) + U256::from(offset); - let entity_id = EntityId::new(copy_fixed(&shard.to_be_bytes::<32>()[0..EntityId::LENGTH])); +pub(crate) fn random_substate_in_shard(shard: Shard, num_shards: u32) -> VersionedSubstateId { + let range = shard.to_substate_address_range(num_shards); + let size = range.end().to_u256() - range.start().to_u256(); + let middlish = range.start().to_u256() + size / 2; + let entity_id = EntityId::new(copy_fixed(&middlish.to_be_bytes()[0..EntityId::LENGTH])); let rand_bytes = OsRng.gen::<[u8; ComponentKey::LENGTH]>(); let component_key = ComponentKey::new(copy_fixed(&rand_bytes)); let substate_id = SubstateId::Component(ComponentAddress::new(ObjectKey::new(entity_id, component_key))); diff --git a/dan_layer/consensus_tests/src/support/transaction.rs b/dan_layer/consensus_tests/src/support/transaction.rs index e7755d482..cb9a4f4dc 100644 --- a/dan_layer/consensus_tests/src/support/transaction.rs +++ b/dan_layer/consensus_tests/src/support/transaction.rs @@ -14,7 +14,7 @@ use tari_engine_types::{ }; use tari_transaction::{SubstateRequirement, Transaction, VersionedSubstateId}; -use crate::support::helpers::random_substate_in_bucket; +use crate::support::helpers::random_substate_in_shard; pub fn build_transaction_from( tx: Transaction, @@ -63,16 +63,21 @@ pub fn build_transaction_from( tx } -pub fn build_transaction(decision: Decision, fee: u64, num_shards: usize, num_committees: u32) -> TransactionRecord { +pub fn build_transaction( + decision: Decision, + fee: u64, + total_num_outputs: usize, + num_committees: u32, +) -> TransactionRecord { let k = PrivateKey::default(); let tx = Transaction::builder().sign(&k).build(); // We create these outputs so that the test VNs dont have to have any UP substates // Equal potion of shards to each committee let outputs = (0..num_committees) - .flat_map(|bucket| { - iter::repeat_with(move || random_substate_in_bucket(bucket.into(), num_committees)) - .take(num_shards / num_committees as usize) + .flat_map(|shard| { + iter::repeat_with(move || random_substate_in_shard(shard.into(), num_committees)) + .take(total_num_outputs.div_ceil(num_committees as usize)) }) .collect::>(); diff --git a/dan_layer/epoch_manager/src/base_layer/base_layer_epoch_manager.rs b/dan_layer/epoch_manager/src/base_layer/base_layer_epoch_manager.rs index 4bfdbeaf2..16158d87e 100644 --- a/dan_layer/epoch_manager/src/base_layer/base_layer_epoch_manager.rs +++ b/dan_layer/epoch_manager/src/base_layer/base_layer_epoch_manager.rs @@ -23,6 +23,7 @@ use std::{ cmp, collections::{HashMap, HashSet}, + num::NonZeroU32, }; use log::*; @@ -629,8 +630,11 @@ impl } } -fn calculate_num_committees(num_vns: u64, committee_size: u32) -> u32 { +fn calculate_num_committees(num_vns: u64, committee_size: NonZeroU32) -> u32 { // Number of committees is proportional to the number of validators available. // We cap the number of committees to u32::MAX (for a committee_size of 10 that's over 42 billion validators) - cmp::min(cmp::max(1, num_vns / u64::from(committee_size)), u64::from(u32::MAX)) as u32 + cmp::min( + cmp::max(1, num_vns / u64::from(committee_size.get())), + u64::from(u32::MAX), + ) as u32 } diff --git a/dan_layer/epoch_manager/src/base_layer/config.rs b/dan_layer/epoch_manager/src/base_layer/config.rs index dda8867ee..49a40b331 100644 --- a/dan_layer/epoch_manager/src/base_layer/config.rs +++ b/dan_layer/epoch_manager/src/base_layer/config.rs @@ -1,11 +1,13 @@ // Copyright 2023 The Tari Project // SPDX-License-Identifier: BSD-3-Clause +use std::num::NonZeroU32; + use tari_common_types::types::PublicKey; #[derive(Debug, Clone)] pub struct EpochManagerConfig { pub base_layer_confirmations: u64, - pub committee_size: u32, + pub committee_size: NonZeroU32, pub validator_node_sidechain_id: Option, }