diff --git a/Cargo.lock b/Cargo.lock index 4a839aecee4..02960b1f481 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -434,7 +434,7 @@ dependencies = [ "log", "parking", "polling", - "rustix 0.37.25", + "rustix 0.37.26", "slab", "socket2 0.4.9", "waker-fn", @@ -736,9 +736,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "bitvec" @@ -855,7 +855,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c79ad7fb2dd38f3dabd76b09c6a5a20c038fc0213ef1e9afd30eb777f120f019" dependencies = [ "memchr", - "regex-automata 0.4.2", + "regex-automata 0.4.3", "serde", ] @@ -1377,9 +1377,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "3fbc60abd742b35f2492f808e1abbb83d45f72db402e14c55057edc9c7b1e9e4" dependencies = [ "libc", ] @@ -2021,9 +2021,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8 0.10.2", "signature 2.1.0", @@ -2050,7 +2050,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" dependencies = [ "curve25519-dalek 4.1.1", - "ed25519 2.2.2", + "ed25519 2.2.3", "rand_core 0.6.4", "serde", "sha2 0.10.8", @@ -2614,7 +2614,7 @@ dependencies = [ [[package]] name = "fuel-core" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "assert_matches", @@ -2663,7 +2663,7 @@ dependencies = [ "tokio-stream", "tower-http", "tracing", - "uuid 1.4.1", + "uuid 1.5.0", ] [[package]] @@ -2687,7 +2687,7 @@ dependencies = [ [[package]] name = "fuel-core-bft" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "parking_lot 0.12.1", @@ -2696,7 +2696,7 @@ dependencies = [ [[package]] name = "fuel-core-bin" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "clap", @@ -2716,7 +2716,7 @@ dependencies = [ [[package]] name = "fuel-core-chain-config" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "bech32 0.9.1", @@ -2735,7 +2735,7 @@ dependencies = [ [[package]] name = "fuel-core-client" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "cynic", @@ -2758,7 +2758,7 @@ dependencies = [ [[package]] name = "fuel-core-client-bin" -version = "0.20.7" +version = "0.20.8" dependencies = [ "clap", "fuel-core-client", @@ -2769,7 +2769,7 @@ dependencies = [ [[package]] name = "fuel-core-consensus-module" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "fuel-core-chain-config", @@ -2781,7 +2781,7 @@ dependencies = [ [[package]] name = "fuel-core-database" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "fuel-core-storage", @@ -2792,7 +2792,7 @@ dependencies = [ [[package]] name = "fuel-core-e2e-client" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "assert_cmd", @@ -2817,7 +2817,7 @@ dependencies = [ [[package]] name = "fuel-core-executor" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "fuel-core-chain-config", @@ -2828,7 +2828,7 @@ dependencies = [ [[package]] name = "fuel-core-importer" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "fuel-core-metrics", @@ -2844,7 +2844,7 @@ dependencies = [ [[package]] name = "fuel-core-keygen" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "clap", @@ -2855,7 +2855,7 @@ dependencies = [ [[package]] name = "fuel-core-metrics" -version = "0.20.7" +version = "0.20.8" dependencies = [ "axum", "once_cell", @@ -2869,7 +2869,7 @@ dependencies = [ [[package]] name = "fuel-core-p2p" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "async-trait", @@ -2912,7 +2912,7 @@ dependencies = [ [[package]] name = "fuel-core-poa" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "async-trait", @@ -2930,7 +2930,7 @@ dependencies = [ [[package]] name = "fuel-core-producer" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "async-trait", @@ -2947,7 +2947,7 @@ dependencies = [ [[package]] name = "fuel-core-relayer" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "async-trait", @@ -2975,7 +2975,7 @@ dependencies = [ [[package]] name = "fuel-core-services" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "async-trait", @@ -2989,7 +2989,7 @@ dependencies = [ [[package]] name = "fuel-core-storage" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "fuel-core-types", @@ -3000,7 +3000,7 @@ dependencies = [ [[package]] name = "fuel-core-sync" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "async-trait", @@ -3046,7 +3046,7 @@ dependencies = [ [[package]] name = "fuel-core-trace" -version = "0.20.7" +version = "0.20.8" dependencies = [ "ctor", "tracing", @@ -3056,7 +3056,7 @@ dependencies = [ [[package]] name = "fuel-core-txpool" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "async-trait", @@ -3082,7 +3082,7 @@ dependencies = [ [[package]] name = "fuel-core-types" -version = "0.20.7" +version = "0.20.8" dependencies = [ "anyhow", "derive_more", @@ -3502,9 +3502,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "hashers" @@ -3879,7 +3879,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" dependencies = [ "equivalent", - "hashbrown 0.14.1", + "hashbrown 0.14.2", ] [[package]] @@ -3977,7 +3977,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix 0.38.19", + "rustix 0.38.20", "windows-sys 0.48.0", ] @@ -4676,9 +4676,9 @@ checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -5048,7 +5048,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "cfg-if", "libc", ] @@ -5276,9 +5276,9 @@ dependencies = [ [[package]] name = "parking" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e52c774a4c39359c1d1c52e43f73dd91a75a614652c825408eec30c95a9b2067" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" @@ -5298,7 +5298,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.8", + "parking_lot_core 0.9.9", ] [[package]] @@ -5317,13 +5317,13 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", + "redox_syscall 0.4.1", "smallvec", "windows-targets 0.48.5", ] @@ -5783,7 +5783,7 @@ checksum = "7c003ac8c77cb07bb74f5f198bce836a689bcd5a42574612bf14d17bfd08c20e" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.4.0", + "bitflags 2.4.1", "lazy_static", "num-traits", "rand 0.8.5", @@ -6099,6 +6099,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_users" version = "0.4.3" @@ -6112,13 +6121,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaac441002f822bc9705a681810a4dd2963094b9ca0ddc41cb963a4c189189ea" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.2", + "regex-automata 0.4.3", "regex-syntax 0.8.2", ] @@ -6133,9 +6142,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5011c7e263a695dc8ca064cddb722af1be54e517a280b12a5356f98366899e5d" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -6250,9 +6259,9 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.3" +version = "0.17.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babe80d5c16becf6594aa32ad2be8fe08498e7ae60b77de8df700e67f191d7e" +checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" dependencies = [ "cc", "getrandom 0.2.10", @@ -6405,9 +6414,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.25" +version = "0.37.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4eb579851244c2c03e7c24f501c3432bed80b8f720af1d6e5b0e0f01555a035" +checksum = "84f3f8f960ed3b5a59055428714943298bf3fa2d4a1d53135084e0544829d995" dependencies = [ "bitflags 1.3.2", "errno", @@ -6419,11 +6428,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.19" +version = "0.38.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed" +checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "errno", "libc", "linux-raw-sys 0.4.10", @@ -6575,9 +6584,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0a159d0c45c12b20c5a844feb1fe4bea86e28f17b92a5f0c42193634d3782" +checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60" dependencies = [ "cfg-if", "derive_more", @@ -6587,9 +6596,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "912e55f6d20e0e80d63733872b40e1227c0bce1e1ab81ba67d696339bfd7fd29" +checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -7280,7 +7289,7 @@ dependencies = [ "cfg-if", "fastrand 2.0.1", "redox_syscall 0.3.5", - "rustix 0.38.19", + "rustix 0.38.20", "windows-sys 0.48.0", ] @@ -7335,18 +7344,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", @@ -7640,9 +7649,9 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.39" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2ef2af84856a50c1d430afce2fdded0a4ec7eda868db86409b4543df0797f9" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "log", "pin-project-lite 0.2.13", @@ -7985,9 +7994,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" dependencies = [ "getrandom 0.2.10", ] @@ -8178,7 +8187,7 @@ version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ - "ring 0.17.3", + "ring 0.17.5", "untrusted 0.9.0", ] @@ -8320,7 +8329,7 @@ dependencies = [ "tokio", "turn", "url", - "uuid 1.4.1", + "uuid 1.5.0", "waitgroup", "webrtc-mdns", "webrtc-util", @@ -8423,7 +8432,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.19", + "rustix 0.38.20", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b1b5149a2dd..d3cd330802c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,32 +45,32 @@ homepage = "https://fuel.network/" keywords = ["blockchain", "cryptocurrencies", "fuel-vm", "vm"] license = "BUSL-1.1" repository = "https://github.com/FuelLabs/fuel-core" -version = "0.20.7" +version = "0.20.8" [workspace.dependencies] # Workspace members -fuel-core = { version = "0.20.7", path = "./crates/fuel-core", default-features = false } -fuel-core-client-bin = { version = "0.20.7", path = "./bin/fuel-core-client" } -fuel-core-bin = { version = "0.20.7", path = "./bin/fuel-core" } -fuel-core-keygen = { version = "0.20.7", path = "./bin/keygen" } -fuel-core-chain-config = { version = "0.20.7", path = "./crates/chain-config" } -fuel-core-client = { version = "0.20.7", path = "./crates/client" } -fuel-core-database = { version = "0.20.7", path = "./crates/database" } -fuel-core-metrics = { version = "0.20.7", path = "./crates/metrics" } -fuel-core-services = { version = "0.20.7", path = "./crates/services" } -fuel-core-consensus-module = { version = "0.20.7", path = "./crates/services/consensus_module" } -fuel-core-bft = { version = "0.20.7", path = "./crates/services/consensus_module/bft" } -fuel-core-poa = { version = "0.20.7", path = "./crates/services/consensus_module/poa" } -fuel-core-executor = { version = "0.20.7", path = "./crates/services/executor" } -fuel-core-importer = { version = "0.20.7", path = "./crates/services/importer" } -fuel-core-p2p = { version = "0.20.7", path = "./crates/services/p2p" } -fuel-core-producer = { version = "0.20.7", path = "./crates/services/producer" } -fuel-core-relayer = { version = "0.20.7", path = "./crates/services/relayer" } -fuel-core-sync = { version = "0.20.7", path = "./crates/services/sync" } -fuel-core-txpool = { version = "0.20.7", path = "./crates/services/txpool" } -fuel-core-storage = { version = "0.20.7", path = "./crates/storage" } -fuel-core-trace = { version = "0.20.7", path = "./crates/trace" } -fuel-core-types = { version = "0.20.7", path = "./crates/types", default-features = false } +fuel-core = { version = "0.20.8", path = "./crates/fuel-core", default-features = false } +fuel-core-client-bin = { version = "0.20.8", path = "./bin/fuel-core-client" } +fuel-core-bin = { version = "0.20.8", path = "./bin/fuel-core" } +fuel-core-keygen = { version = "0.20.8", path = "./bin/keygen" } +fuel-core-chain-config = { version = "0.20.8", path = "./crates/chain-config" } +fuel-core-client = { version = "0.20.8", path = "./crates/client" } +fuel-core-database = { version = "0.20.8", path = "./crates/database" } +fuel-core-metrics = { version = "0.20.8", path = "./crates/metrics" } +fuel-core-services = { version = "0.20.8", path = "./crates/services" } +fuel-core-consensus-module = { version = "0.20.8", path = "./crates/services/consensus_module" } +fuel-core-bft = { version = "0.20.8", path = "./crates/services/consensus_module/bft" } +fuel-core-poa = { version = "0.20.8", path = "./crates/services/consensus_module/poa" } +fuel-core-executor = { version = "0.20.8", path = "./crates/services/executor" } +fuel-core-importer = { version = "0.20.8", path = "./crates/services/importer" } +fuel-core-p2p = { version = "0.20.8", path = "./crates/services/p2p" } +fuel-core-producer = { version = "0.20.8", path = "./crates/services/producer" } +fuel-core-relayer = { version = "0.20.8", path = "./crates/services/relayer" } +fuel-core-sync = { version = "0.20.8", path = "./crates/services/sync" } +fuel-core-txpool = { version = "0.20.8", path = "./crates/services/txpool" } +fuel-core-storage = { version = "0.20.8", path = "./crates/storage" } +fuel-core-trace = { version = "0.20.8", path = "./crates/trace" } +fuel-core-types = { version = "0.20.8", path = "./crates/types", default-features = false } fuel-core-tests = { version = "0.0.0", path = "./tests" } fuel-core-xtask = { version = "0.0.0", path = "./xtask" } diff --git a/crates/fuel-core/src/p2p_test_helpers.rs b/crates/fuel-core/src/p2p_test_helpers.rs index 6243acabeaf..e27be5d3437 100644 --- a/crates/fuel-core/src/p2p_test_helpers.rs +++ b/crates/fuel-core/src/p2p_test_helpers.rs @@ -14,6 +14,8 @@ use crate::{ use fuel_core_p2p::{ codecs::postcard::PostcardCodec, network_service::FuelP2PService, + p2p_service::FuelP2PEvent, + service::to_message_acceptance, }; use fuel_core_poa::{ ports::BlockImporter, @@ -43,6 +45,7 @@ use fuel_core_types::{ Bytes32, }, secrecy::Secret, + services::p2p::GossipsubMessageAcceptance, }; use futures::StreamExt; use itertools::Itertools; @@ -62,6 +65,12 @@ use std::{ }; use tokio::sync::broadcast; +#[derive(Copy, Clone)] +pub enum BootstrapType { + BootstrapNodes, + ReservedNodes, +} + #[derive(Clone)] /// Setup for a producer node pub struct ProducerSetup { @@ -71,6 +80,10 @@ pub struct ProducerSetup { pub secret: SecretKey, /// Number of test transactions to create for this producer. pub num_test_txs: usize, + /// Enable full utxo stateful validation. + pub utxo_validation: bool, + /// Indicates the type of initial connections. + pub bootstrap_type: BootstrapType, } #[derive(Clone)] @@ -80,6 +93,10 @@ pub struct ValidatorSetup { pub name: String, /// Public key of the producer to sync from. pub pub_key: Address, + /// Enable full utxo stateful validation. + pub utxo_validation: bool, + /// Indicates the type of initial connections. + pub bootstrap_type: BootstrapType, } #[derive(Clone)] @@ -126,7 +143,20 @@ impl Bootstrap { assert!(result.is_ok()); break; } - _ = bootstrap.next_event() => {} + event = bootstrap.next_event() => { + // The bootstrap node only forwards data without validating it. + if let Some(FuelP2PEvent::GossipsubMessage { + peer_id, + message_id, + .. + }) = event { + bootstrap.report_message_validation_result( + &message_id, + peer_id, + to_message_acceptance(&GossipsubMessageAcceptance::Accept) + ) + } + } } } }); @@ -253,9 +283,27 @@ pub async fn make_nodes( let mut test_txs = Vec::with_capacity(0); node_config.block_production = Trigger::Instant; - node_config.p2p.as_mut().unwrap().bootstrap_nodes = boots.clone(); - if let Some((ProducerSetup { secret, .. }, txs)) = s { + if let Some(( + ProducerSetup { + secret, + utxo_validation, + bootstrap_type, + .. + }, + txs, + )) = s + { + match bootstrap_type { + BootstrapType::BootstrapNodes => { + node_config.p2p.as_mut().unwrap().bootstrap_nodes = boots.clone(); + } + BootstrapType::ReservedNodes => { + node_config.p2p.as_mut().unwrap().reserved_nodes = boots.clone(); + } + } + + node_config.utxo_validation = utxo_validation; let pub_key = secret.public_key(); match &mut node_config.chain_conf.consensus { crate::chain_config::ConsensusConfig::PoA { signing_key } => { @@ -283,9 +331,24 @@ pub async fn make_nodes( chain_config.clone(), ); node_config.block_production = Trigger::Never; - node_config.p2p.as_mut().unwrap().bootstrap_nodes = boots.clone(); - if let Some(ValidatorSetup { pub_key, .. }) = s { + if let Some(ValidatorSetup { + pub_key, + utxo_validation, + bootstrap_type, + .. + }) = s + { + node_config.utxo_validation = utxo_validation; + + match bootstrap_type { + BootstrapType::BootstrapNodes => { + node_config.p2p.as_mut().unwrap().bootstrap_nodes = boots.clone(); + } + BootstrapType::ReservedNodes => { + node_config.p2p.as_mut().unwrap().reserved_nodes = boots.clone(); + } + } match &mut node_config.chain_conf.consensus { crate::chain_config::ConsensusConfig::PoA { signing_key } => { *signing_key = pub_key; @@ -340,6 +403,11 @@ fn extract_p2p_config(node_config: &Config) -> fuel_core_p2p::config::Config { } impl Node { + /// Returns the vector of valid transactions for pre-initialized state. + pub fn test_transactions(&self) -> &Vec { + &self.test_txs + } + /// Waits for `number_of_blocks` and each block should be `is_local` pub async fn wait_for_blocks(&self, number_of_blocks: usize, is_local: bool) { let mut stream = self @@ -450,6 +518,8 @@ impl ProducerSetup { name: Default::default(), secret, num_test_txs: Default::default(), + utxo_validation: true, + bootstrap_type: BootstrapType::BootstrapNodes, } } @@ -466,6 +536,20 @@ impl ProducerSetup { ..self } } + + pub fn utxo_validation(self, utxo_validation: bool) -> Self { + Self { + utxo_validation, + ..self + } + } + + pub fn bootstrap_type(self, bootstrap_type: BootstrapType) -> Self { + Self { + bootstrap_type, + ..self + } + } } impl ValidatorSetup { @@ -473,6 +557,8 @@ impl ValidatorSetup { Self { pub_key, name: Default::default(), + utxo_validation: true, + bootstrap_type: BootstrapType::BootstrapNodes, } } @@ -482,6 +568,20 @@ impl ValidatorSetup { ..self } } + + pub fn utxo_validation(self, utxo_validation: bool) -> Self { + Self { + utxo_validation, + ..self + } + } + + pub fn bootstrap_type(self, bootstrap_type: BootstrapType) -> Self { + Self { + bootstrap_type, + ..self + } + } } impl BootstrapSetup { pub fn new(pub_key: Address) -> Self { diff --git a/crates/services/consensus_module/poa/src/service.rs b/crates/services/consensus_module/poa/src/service.rs index fc42fc8d49e..2e050b57bae 100644 --- a/crates/services/consensus_module/poa/src/service.rs +++ b/crates/services/consensus_module/poa/src/service.rs @@ -154,7 +154,7 @@ where p2p_port: P, ) -> Self { let tx_status_update_stream = txpool.transaction_status_events(); - let (request_sender, request_receiver) = mpsc::channel(100); + let (request_sender, request_receiver) = mpsc::channel(1024); let (last_height, last_timestamp, last_block_created) = Self::extract_block_info(last_block); diff --git a/crates/services/p2p/src/lib.rs b/crates/services/p2p/src/lib.rs index 83ad440dfdf..5db0022f95f 100644 --- a/crates/services/p2p/src/lib.rs +++ b/crates/services/p2p/src/lib.rs @@ -1,14 +1,14 @@ -mod behavior; +pub mod behavior; pub mod codecs; pub mod config; -mod discovery; -mod gossipsub; -mod heartbeat; -mod p2p_service; -mod peer_manager; -mod peer_report; +pub mod discovery; +pub mod gossipsub; +pub mod heartbeat; +pub mod p2p_service; +pub mod peer_manager; +pub mod peer_report; pub mod ports; -mod request_response; +pub mod request_response; pub mod service; pub use gossipsub::config as gossipsub_config; diff --git a/crates/services/p2p/src/p2p_service.rs b/crates/services/p2p/src/p2p_service.rs index d0236ca0822..386119eaa10 100644 --- a/crates/services/p2p/src/p2p_service.rs +++ b/crates/services/p2p/src/p2p_service.rs @@ -377,8 +377,15 @@ impl FuelP2PService { &mut self, msg_id: &MessageId, propagation_source: PeerId, - acceptance: MessageAcceptance, + mut acceptance: MessageAcceptance, ) { + // Even invalid transactions shouldn't affect reserved peer reputation. + if let MessageAcceptance::Reject = acceptance { + if self.peer_manager.is_reserved(&propagation_source) { + acceptance = MessageAcceptance::Ignore; + } + } + if let Some(gossip_score) = self .swarm .behaviour_mut() diff --git a/crates/services/p2p/src/peer_manager.rs b/crates/services/p2p/src/peer_manager.rs index e65ad104ea6..5489ce25b12 100644 --- a/crates/services/p2p/src/peer_manager.rs +++ b/crates/services/p2p/src/peer_manager.rs @@ -97,6 +97,10 @@ impl PeerManager { self.reserved_peers_updates.clone() } + pub fn is_reserved(&self, peer_id: &PeerId) -> bool { + self.reserved_peers.contains(peer_id) + } + pub fn handle_gossip_score_update( &self, peer_id: PeerId, diff --git a/crates/services/p2p/src/service.rs b/crates/services/p2p/src/service.rs index bbb6af26c57..47394624bff 100644 --- a/crates/services/p2p/src/service.rs +++ b/crates/services/p2p/src/service.rs @@ -108,7 +108,35 @@ enum TaskRequest { impl Debug for TaskRequest { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "TaskRequest") + match self { + TaskRequest::BroadcastTransaction(_) => { + write!(f, "TaskRequest::BroadcastTransaction") + } + TaskRequest::BroadcastBlock(_) => { + write!(f, "TaskRequest::BroadcastBlock") + } + TaskRequest::BroadcastVote(_) => { + write!(f, "TaskRequest::BroadcastVote") + } + TaskRequest::GetPeerIds(_) => { + write!(f, "TaskRequest::GetPeerIds") + } + TaskRequest::GetBlock { .. } => { + write!(f, "TaskRequest::GetBlock") + } + TaskRequest::GetSealedHeader { .. } => { + write!(f, "TaskRequest::GetSealedHeader") + } + TaskRequest::GetTransactions { .. } => { + write!(f, "TaskRequest::GetTransactions") + } + TaskRequest::RespondWithGossipsubMessageReport(_) => { + write!(f, "TaskRequest::RespondWithGossipsubMessageReport") + } + TaskRequest::RespondWithPeerReport { .. } => { + write!(f, "TaskRequest::RespondWithPeerReport") + } + } } } @@ -131,9 +159,9 @@ impl Task { db: Arc, block_importer: Arc, ) -> Self { - let (request_sender, request_receiver) = mpsc::channel(100); - let (tx_broadcast, _) = broadcast::channel(100); - let (block_height_broadcast, _) = broadcast::channel(100); + let (request_sender, request_receiver) = mpsc::channel(1024 * 10); + let (tx_broadcast, _) = broadcast::channel(1024 * 10); + let (block_height_broadcast, _) = broadcast::channel(1024 * 10); let next_block_height = block_importer.next_block_height(); let max_block_size = config.max_block_size; @@ -506,7 +534,7 @@ where )) } -pub(crate) fn to_message_acceptance( +pub fn to_message_acceptance( acceptance: &GossipsubMessageAcceptance, ) -> MessageAcceptance { match acceptance { diff --git a/deployment/charts/Chart.yaml b/deployment/charts/Chart.yaml index 370aeffbb9d..a5f37afeb11 100644 --- a/deployment/charts/Chart.yaml +++ b/deployment/charts/Chart.yaml @@ -2,5 +2,5 @@ apiVersion: v2 name: ${fuel_core_service_name} description: ${fuel_core_service_name} Helm Chart type: application -appVersion: "0.20.7" +appVersion: "0.20.8" version: 0.1.0 diff --git a/tests/tests/tx_gossip.rs b/tests/tests/tx_gossip.rs index 8e9f293b1be..06a7bfd2636 100644 --- a/tests/tests/tx_gossip.rs +++ b/tests/tests/tx_gossip.rs @@ -1,15 +1,21 @@ use fuel_core::p2p_test_helpers::{ make_nodes, BootstrapSetup, + BootstrapType, Nodes, ProducerSetup, ValidatorSetup, }; -use fuel_core_client::client::FuelClient; +use fuel_core_client::client::{ + types::TransactionStatus, + FuelClient, +}; +use fuel_core_poa::ports::BlockImporter; use fuel_core_types::{ fuel_tx::*, fuel_vm::*, }; +use futures::StreamExt; use rand::{ rngs::StdRng, SeedableRng, @@ -20,12 +26,12 @@ use std::{ Hash, Hasher, }, + io, time::Duration, }; #[tokio::test(flavor = "multi_thread")] async fn test_tx_gossiping() { - use futures::StreamExt; // Create a random seed based on the test parameters. let mut hasher = DefaultHasher::new(); let num_txs = 1; @@ -90,3 +96,129 @@ async fn test_tx_gossiping() { let response = client_two.transaction(&tx_id).await.unwrap(); assert!(response.is_some()); } + +const NUMBER_OF_INVALID_TXS: usize = 100; + +async fn test_tx_gossiping_invalid_txs( + bootstrap_type: BootstrapType, +) -> io::Result { + // Create a random seed based on the test parameters. + let mut hasher = DefaultHasher::new(); + let num_txs = 1; + let num_validators = 1; + let num_partitions = 1; + (num_txs, num_validators, num_partitions, line!()).hash(&mut hasher); + let mut rng = StdRng::seed_from_u64(hasher.finish()); + + // Create a set of key pairs. + let secrets: Vec<_> = (0..1).map(|_| SecretKey::random(&mut rng)).collect(); + let pub_keys: Vec<_> = secrets + .clone() + .into_iter() + .map(|secret| Input::owner(&secret.public_key())) + .collect(); + + // Create a producer for each key pair and a set of validators that share + // the same key pair. + let Nodes { + producers, + validators, + bootstrap_nodes: _dont_drop, + } = make_nodes( + pub_keys + .iter() + .map(|pub_key| Some(BootstrapSetup::new(*pub_key))), + secrets.clone().into_iter().enumerate().map(|(i, secret)| { + Some( + ProducerSetup::new(secret) + .with_txs(num_txs) + .with_name(format!("{}:producer", pub_keys[i])) + .bootstrap_type(bootstrap_type), + ) + }), + pub_keys.iter().flat_map(|pub_key| { + (0..num_validators).map(move |i| { + Some( + ValidatorSetup::new(*pub_key) + .with_name(format!("{pub_key}:{i}")) + .bootstrap_type(bootstrap_type) + // Validator wants to send invalid transactions. + .utxo_validation(false), + ) + }) + }), + ) + .await; + + let authority = &producers[0]; + let sentry = &validators[0]; + + // Time for nodes to connect to each other. + tokio::time::sleep(Duration::from_secs(2)).await; + + use rand::Rng; + + for _ in 0..NUMBER_OF_INVALID_TXS { + let invalid_tx = TransactionBuilder::script(vec![], vec![]) + .add_unsigned_coin_input( + rng.gen(), + rng.gen(), + rng.gen(), + rng.gen(), + Default::default(), + Default::default(), + ) + .finalize() + .into(); + + sentry.node.submit(invalid_tx).await.expect( + "Should accept invalid transaction because `utxo_validation = false`.", + ); + } + + // Give some time to receive all invalid transactions. + tokio::time::sleep(Duration::from_secs(5)).await; + + let mut authority_blocks = authority.node.shared.block_importer.block_stream(); + + // Submit a valid transaction from banned sentry to an authority node. + let valid_transaction = authority.test_transactions()[0].clone(); + sentry + .node + .submit(valid_transaction.clone()) + .await + .expect("Transaction is valid"); + let _ = tokio::time::timeout(Duration::from_secs(5), authority_blocks.next()).await; + + let authority_client = FuelClient::from(authority.node.bound_address); + authority_client + .transaction_status(&valid_transaction.id(&Default::default())) + .await +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_tx_gossiping_reserved_nodes_invalid_txs() { + // Test verifies that gossiping of invalid transactions from reserved + // nodes doesn't decrease its reputation. + // After gossiping `NUMBER_OF_INVALID_TXS` transactions, + // we will gossip one valid transaction, and it should be included. + let status = test_tx_gossiping_invalid_txs(BootstrapType::ReservedNodes).await; + + assert!(matches!( + status, + Ok(fuel_core_client::client::types::TransactionStatus::Success { .. }) + )); +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_tx_gossiping_non_reserved_nodes_invalid_txs() { + // This test is opposite to the `test_tx_gossiping_reserved_nodes_invalid_txs`. + // It verifies that gossiping about invalid transactions from + // non-reserved peers disconnects them. + // + // The test sends `NUMBER_OF_INVALID_TXS` invalid transactions, + // and verifies that sending a valid one will be ignored. + let status = test_tx_gossiping_invalid_txs(BootstrapType::BootstrapNodes).await; + + assert!(status.is_err()); +}