From 93d2eb8ec0175047c1b64207807e5e083c94ec90 Mon Sep 17 00:00:00 2001 From: x19 <100000306+0xNineteen@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:11:19 -0400 Subject: [PATCH] fix(rand): remove timestamp randomness (#257) - changed the imports across various files to match the current approach (sig.core.account; not @import) - remove excess path naming of tests (test "bloom.bloom: ..." -> test "...") - move `getWallclockMs` into `sig.time` (doesnt make sense to be in gossip) - add seed parameter to `buildMessages` which is used for all random operations (prev seed was wallclock) - add `seed` parameter to `PullRequestTask` (instead of using wallclock) - add `now` parameter to `buildPullRequests` for more deterministic results (prev was reading wallclock) - modifications to `test "test build pull requests"` to be a more deterministic test note: the last two changes were aimed to make `test "test build pull requests"` more deterministic and fix https://github.com/Syndica/sig/issues/157 -- ive re-run the tests many times and it seems to be fixed - remove unnecessary log lines in gossip - add additional context to readme.md --- metrics/README.md | 2 + readme.md | 5 +++ src/accountsdb/accounts_file.zig | 13 ++++--- src/accountsdb/bank.zig | 1 - src/accountsdb/db.zig | 3 +- src/accountsdb/fuzz_snapshot.zig | 1 - src/accountsdb/index.zig | 24 ++++++------ src/accountsdb/lib.zig | 1 + src/accountsdb/snapshots.zig | 4 +- src/bloom/bloom.zig | 10 ++--- src/cmd/cmd.zig | 4 +- src/gossip/active_set.zig | 11 +++--- src/gossip/data.zig | 57 +++++++++++++---------------- src/gossip/dump_service.zig | 9 +++-- src/gossip/fuzz_service.zig | 9 ++--- src/gossip/fuzz_table.zig | 2 - src/gossip/lib.zig | 2 - src/gossip/message.zig | 37 +++++++++---------- src/gossip/ping_pong.zig | 7 ++-- src/gossip/pull_request.zig | 50 ++++++++++++++----------- src/gossip/pull_response.zig | 29 +++++++-------- src/gossip/service.zig | 63 ++++++++++++++++---------------- src/gossip/shards.zig | 18 ++++----- src/gossip/table.zig | 11 +++--- src/net/lib.zig | 1 + src/net/net.zig | 10 ++--- src/rpc/client.zig | 2 +- src/time/lib.zig | 6 +++ 28 files changed, 197 insertions(+), 195 deletions(-) diff --git a/metrics/README.md b/metrics/README.md index 7ef9395fd..d0cb57fde 100644 --- a/metrics/README.md +++ b/metrics/README.md @@ -4,6 +4,7 @@ original src: https://github.com/docker/awesome-compose/tree/master/prometheus-g requirements: - `docker compose` + - [https://docs.docker.com/engine/install/ubuntu/](https://docs.docker.com/engine/install/ubuntu/) - either mac or linux supported modify `/etc/hosts` to include the following line: @@ -11,6 +12,7 @@ modify `/etc/hosts` to include the following line: 127.0.0.1 prometheus ``` + ## Running mac: `docker compose -f compose_mac.yaml up -d` diff --git a/readme.md b/readme.md index 5d71c33dc..ec2d75703 100644 --- a/readme.md +++ b/readme.md @@ -33,6 +33,11 @@ metrics ├─ grafana/ scripts/ src/ +├─ main.zig # exec entrypoint +├─ sig.zig # library entrypoint +├─ tests.zig +├─ fuzz.zig +├─ benchmarks.zig ``` diff --git a/src/accountsdb/accounts_file.zig b/src/accountsdb/accounts_file.zig index 530697cb0..603c4cf5a 100644 --- a/src/accountsdb/accounts_file.zig +++ b/src/accountsdb/accounts_file.zig @@ -2,14 +2,15 @@ const std = @import("std"); const sig = @import("../sig.zig"); -const Account = sig.core.Account; -const writeIntLittleMem = sig.core.account.writeIntLittleMem; -const Hash = sig.core.Hash; -const Slot = sig.core.Slot; -const Epoch = sig.core.Epoch; -const Pubkey = sig.core.Pubkey; +const Account = sig.core.account.Account; +const Hash = sig.core.hash.Hash; +const Slot = sig.core.time.Slot; +const Epoch = sig.core.time.Epoch; +const Pubkey = sig.core.pubkey.Pubkey; const AccountFileInfo = sig.accounts_db.snapshots.AccountFileInfo; +const writeIntLittleMem = sig.core.account.writeIntLittleMem; + /// Simple strictly-typed alias for an integer, used to represent a file ID. /// /// Analogous to [AccountsFileId](https://github.com/anza-xyz/agave/blob/4c921ca276bbd5997f809dec1dd3937fb06463cc/accounts-db/src/accounts_db.rs#L824) diff --git a/src/accountsdb/bank.zig b/src/accountsdb/bank.zig index 25af0d098..940dfb072 100644 --- a/src/accountsdb/bank.zig +++ b/src/accountsdb/bank.zig @@ -1,5 +1,4 @@ //! minimal logic for bank (still being built out) - const std = @import("std"); const sig = @import("../sig.zig"); diff --git a/src/accountsdb/db.zig b/src/accountsdb/db.zig index f3e5f47e9..6b90e9a9f 100644 --- a/src/accountsdb/db.zig +++ b/src/accountsdb/db.zig @@ -562,10 +562,9 @@ pub const AccountsDB = struct { // read accounts file var accounts_file = blk: { const file_name_bounded = sig.utils.fmt.boundedFmt("{d}.{d}", .{ slot, file_info.id.toInt() }); - errdefer std.debug.print("failed to open file: {s}\n", .{file_name_bounded.constSlice()}); const accounts_file_file = accounts_dir.openFile(file_name_bounded.constSlice(), .{ .mode = .read_write }) catch |err| { - self.logger.errf("Failed to open accounts/{s}", .{file_name_bounded.constSlice()}); + self.logger.errf("Failed to open accounts/{s}: {s}", .{ file_name_bounded.constSlice(), @errorName(err) }); return err; }; errdefer accounts_file_file.close(); diff --git a/src/accountsdb/fuzz_snapshot.zig b/src/accountsdb/fuzz_snapshot.zig index 5f9406bcc..91dd6a2fc 100644 --- a/src/accountsdb/fuzz_snapshot.zig +++ b/src/accountsdb/fuzz_snapshot.zig @@ -1,5 +1,4 @@ const std = @import("std"); - const sig = @import("../sig.zig"); const bincode = sig.bincode; diff --git a/src/accountsdb/index.zig b/src/accountsdb/index.zig index 57add582d..3f2fa1e5e 100644 --- a/src/accountsdb/index.zig +++ b/src/accountsdb/index.zig @@ -1,18 +1,16 @@ //! all index related structs (account ref, simd hashmap, …) - const std = @import("std"); -const lib = @import("../sig.zig"); - -const Slot = lib.core.time.Slot; -const Pubkey = lib.core.pubkey.Pubkey; -const FileId = lib.accounts_db.accounts_file.FileId; -const RwMux = lib.sync.RwMux; - -const swiss_map = @import("swiss_map.zig"); -pub const SwissMapManaged = swiss_map.SwissMapManaged; -pub const SwissMapUnmanaged = swiss_map.SwissMapUnmanaged; -pub const BenchmarkSwissMap = swiss_map.BenchmarkSwissMap; -pub const BenchHashMap = swiss_map.BenchHashMap; +const sig = @import("../sig.zig"); + +const Slot = sig.core.time.Slot; +const Pubkey = sig.core.pubkey.Pubkey; +const FileId = sig.accounts_db.accounts_file.FileId; +const RwMux = sig.sync.RwMux; + +pub const SwissMapManaged = sig.accounts_db.swiss_map.SwissMapManaged; +pub const SwissMapUnmanaged = sig.accounts_db.swiss_map.SwissMapUnmanaged; +pub const BenchHashMap = sig.accounts_db.swiss_map.BenchHashMap; +pub const BenchmarkSwissMap = sig.accounts_db.swiss_map.BenchmarkSwissMap; // for sync reasons we need a stable head with a lock pub const AccountReferenceHead = RwMux(struct { diff --git a/src/accountsdb/lib.zig b/src/accountsdb/lib.zig index 830bbe3d6..db33ab178 100644 --- a/src/accountsdb/lib.zig +++ b/src/accountsdb/lib.zig @@ -8,6 +8,7 @@ pub const snapshots = @import("snapshots.zig"); pub const sysvars = @import("sysvars.zig"); pub const fuzz = @import("fuzz.zig"); pub const fuzz_snapshot = @import("fuzz_snapshot.zig"); +pub const swiss_map = @import("swiss_map.zig"); pub const AccountsDB = db.AccountsDB; pub const AllSnapshotFields = snapshots.AllSnapshotFields; diff --git a/src/accountsdb/snapshots.zig b/src/accountsdb/snapshots.zig index 102ce9d2a..2a9e034a1 100644 --- a/src/accountsdb/snapshots.zig +++ b/src/accountsdb/snapshots.zig @@ -1854,7 +1854,7 @@ pub fn parallelUnpackZstdTarBall( ); } -test "test full snapshot path parsing" { +test "full snapshot path parsing" { const full_snapshot_path = "snapshot-269-EAHHZCVccCdAoCXH8RWxvv9edcwjY2boqni9MJuh3TCn.tar.zst"; const snapshot_info = try FullSnapshotFileInfo.fromString(full_snapshot_path); @@ -1863,7 +1863,7 @@ test "test full snapshot path parsing" { try std.testing.expectEqual(.zstd, snapshot_info.compression); } -test "test incremental snapshot path parsing" { +test "incremental snapshot path parsing" { const path = "incremental-snapshot-269-307-4JLFzdaaqkSrmHs55bBDhZrQjHYZvqU1vCcQ5mP22pdB.tar.zst"; const snapshot_info = try IncrementalSnapshotFileInfo.fromString(path); diff --git a/src/bloom/bloom.zig b/src/bloom/bloom.zig index 7e8c387c0..5aa55321b 100644 --- a/src/bloom/bloom.zig +++ b/src/bloom/bloom.zig @@ -119,7 +119,7 @@ pub const Bloom = struct { } }; -test "bloom.bloom: helper fcns match rust" { +test "helper methods match rust" { const n_bits = Bloom.numBits(100.2, 1e-5); try testing.expectEqual(@as(f64, 2402), n_bits); @@ -131,7 +131,7 @@ test "bloom.bloom: helper fcns match rust" { defer bloom.deinit(); } -test "bloom.bloom: serializes/deserializes correctly" { +test "serializes/deserializes correctly" { const bloom = Bloom.init(testing.allocator, 0, null); var buf: [10000]u8 = undefined; @@ -145,7 +145,7 @@ test "bloom.bloom: serializes/deserializes correctly" { try testing.expect(bloom.num_bits_set == deserialized.num_bits_set); } -test "bloom.bloom: serializes/deserializes correctly with set bits" { +test "serializes/deserializes correctly with set bits" { var bloom = Bloom.init(testing.allocator, 128, null); try bloom.addKey(10); // required for memory leaks @@ -160,7 +160,7 @@ test "bloom.bloom: serializes/deserializes correctly with set bits" { try testing.expect(bloom.num_bits_set == deserialized.num_bits_set); } -test "bloom.bloom: rust: serialized bytes equal rust (one key)" { +test "serialized bytes equal rust (one key)" { // note: need to init with len 2^i var bloom = Bloom.init(testing.allocator, 128, null); defer bloom.deinit(); @@ -177,7 +177,7 @@ test "bloom.bloom: rust: serialized bytes equal rust (one key)" { try testing.expectEqualSlices(u8, &rust_bytes, bytes[0..bytes.len]); } -test "bloom.bloom: rust: serialized bytes equal rust (multiple keys)" { +test "serialized bytes equal rust (multiple keys)" { var bloom = Bloom.init(testing.allocator, 128, null); defer bloom.deinit(); diff --git a/src/cmd/cmd.zig b/src/cmd/cmd.zig index 3d2309ae2..0495cdba6 100644 --- a/src/cmd/cmd.zig +++ b/src/cmd/cmd.zig @@ -28,7 +28,7 @@ const StatusCache = sig.accounts_db.StatusCache; const downloadSnapshotsFromGossip = sig.accounts_db.downloadSnapshotsFromGossip; const getOrInitIdentity = helpers.getOrInitIdentity; const globalRegistry = sig.prometheus.globalRegistry; -const getWallclockMs = sig.gossip.getWallclockMs; +const getWallclockMs = sig.time.getWallclockMs; const leaderScheduleFromBank = sig.core.leader_schedule.leaderScheduleFromBank; const parallelUnpackZstdTarBall = sig.accounts_db.parallelUnpackZstdTarBall; const parseLeaderSchedule = sig.core.leader_schedule.parseLeaderSchedule; @@ -909,7 +909,7 @@ fn validateSnapshot() !void { allocator, app_base.logger, null, - false, + true, geyser_writer, ); defer snapshot_result.deinit(); diff --git a/src/gossip/active_set.zig b/src/gossip/active_set.zig index 6c8b0bb59..a995b80d1 100644 --- a/src/gossip/active_set.zig +++ b/src/gossip/active_set.zig @@ -12,7 +12,7 @@ const LegacyContactInfo = sig.gossip.data.LegacyContactInfo; const ThreadSafeContactInfo = sig.gossip.data.ThreadSafeContactInfo; const GossipTable = sig.gossip.table.GossipTable; -const getWallclockMs = sig.gossip.getWallclockMs; +const getWallclockMs = sig.time.getWallclockMs; const shuffleFirstN = sig.gossip.pull_request.shuffleFirstN; const NUM_ACTIVE_SET_ENTRIES: usize = 25; @@ -128,7 +128,7 @@ pub const ActiveSet = struct { } }; -test "gossip.active_set: init/deinit" { +test "init/denit" { const alloc = std.testing.allocator; const ThreadPool = @import("../sync/thread_pool.zig").ThreadPool; @@ -154,8 +154,7 @@ test "gossip.active_set: init/deinit" { var active_set = ActiveSet.init(alloc); defer active_set.deinit(); - var prng = std.Random.Xoshiro256.init(@intCast(std.time.milliTimestamp())); - try active_set.rotate(prng.random(), gossip_peers.items); + try active_set.rotate(rng.random(), gossip_peers.items); try std.testing.expect(active_set.len() == GOSSIP_PUSH_FANOUT); @@ -175,7 +174,7 @@ test "gossip.active_set: init/deinit" { try std.testing.expectEqual(no_prune_fanout_len, fanout_with_prune.items.len + 1); } -test "gossip.active_set: gracefully rotates with duplicate contact ids" { +test "gracefully rotates with duplicate contact ids" { const alloc = std.testing.allocator; var rng = std.rand.DefaultPrng.init(100); @@ -192,6 +191,6 @@ test "gossip.active_set: gracefully rotates with duplicate contact ids" { var active_set = ActiveSet.init(alloc); defer active_set.deinit(); - var prng = std.Random.Xoshiro256.init(@intCast(std.time.milliTimestamp())); + var prng = std.rand.Xoshiro256.init(@intCast(std.time.milliTimestamp())); try active_set.rotate(prng.random(), gossip_peers.items); } diff --git a/src/gossip/data.zig b/src/gossip/data.zig index 514beab20..42b438647 100644 --- a/src/gossip/data.zig +++ b/src/gossip/data.zig @@ -9,7 +9,6 @@ const ArrayList = std.ArrayList; const KeyPair = std.crypto.sign.Ed25519.KeyPair; const UdpSocket = network.Socket; const TcpListener = network.Socket; - const SocketAddr = sig.net.SocketAddr; const Hash = sig.core.Hash; const Signature = sig.core.Signature; @@ -19,20 +18,16 @@ const Pubkey = sig.core.Pubkey; const IpAddr = sig.net.IpAddr; const ClientVersion = sig.version.ClientVersion; const DynamicArrayBitSet = sig.bloom.bit_set.DynamicArrayBitSet; + +const getWallclockMs = sig.time.getWallclockMs; const BitVecConfig = sig.bloom.bit_vec.BitVecConfig; const ShortVecArrayListConfig = sig.bincode.shortvec.ShortVecArrayListConfig; - const sanitizeWallclock = sig.gossip.message.sanitizeWallclock; const PACKET_DATA_SIZE = sig.net.packet.PACKET_DATA_SIZE; const var_int_config_u16 = sig.bincode.varint.var_int_config_u16; const var_int_config_u64 = sig.bincode.varint.var_int_config_u64; -/// returns current timestamp in milliseconds -pub fn getWallclockMs() u64 { - return @intCast(std.time.milliTimestamp()); -} - pub const MAX_EPOCH_SLOTS: u8 = 255; pub const MAX_VOTES: u8 = 32; pub const MAX_SLOT: u64 = 1_000_000_000_000_000; @@ -1560,7 +1555,7 @@ const RawOffsets = struct { } }; -test "gossip.data: new contact info" { +test "new contact info" { const seed: u64 = @intCast(std.time.milliTimestamp()); var rand = std.rand.DefaultPrng.init(seed); const rng = rand.random(); @@ -1569,7 +1564,7 @@ test "gossip.data: new contact info" { defer ci.deinit(); } -test "gossip.data: socketaddr bincode serialize matches rust" { +test "socketaddr bincode serialize matches rust" { const Tmp = struct { addr: SocketAddr, }; @@ -1589,7 +1584,7 @@ test "gossip.data: socketaddr bincode serialize matches rust" { try testing.expectEqualSlices(u8, rust_bytes[0..rust_bytes.len], bytes); } -test "gossip.data: set & get socket on contact info" { +test "set & get socket on contact info" { const seed: u64 = @intCast(std.time.milliTimestamp()); var rand = std.rand.DefaultPrng.init(seed); const rng = rand.random(); @@ -1604,7 +1599,7 @@ test "gossip.data: set & get socket on contact info" { try testing.expect(ci.sockets.items[0].eql(&.{ .key = .rpc, .index = 0, .offset = 8899 })); } -test "gossip.data: contact info bincode serialize matches rust bincode" { +test "contact info bincode serialize matches rust bincode" { // ContactInfo generated using rust ConfigInfo::new_rand(..., ...); and printed in debug format // ContactInfo serialized using rust bincode // @@ -1723,7 +1718,7 @@ test "gossip.data: contact info bincode serialize matches rust bincode" { try testing.expect(sig_contact_info_deserialised.outset == sig_contact_info.outset); } -test "gossip.data: ContactInfo bincode roundtrip maintains data integrity" { +test "ContactInfo bincode roundtrip maintains data integrity" { var contact_info_bytes_from_mainnet = [109]u8{ 168, 36, 147, 159, 43, 110, 51, 177, 21, 191, 96, 206, 25, 12, 133, 238, 147, 223, 2, 133, 105, 29, 83, 234, @@ -1748,7 +1743,7 @@ test "gossip.data: ContactInfo bincode roundtrip maintains data integrity" { try testing.expect(std.mem.eql(u8, buf.items, &contact_info_bytes_from_mainnet)); } -test "gossip.data: SocketEntry serializer works" { +test "SocketEntry serializer works" { testing.log_level = .debug; comptime std.debug.assert(@intFromEnum(SocketTag.rpc_pubsub) == 3); @@ -1766,7 +1761,7 @@ test "gossip.data: SocketEntry serializer works" { try testing.expect(other_se.offset == se.offset); } -test "gossip.data: test sig verify duplicateShreds" { +test "sig verify duplicateShreds" { var keypair = try KeyPair.create([_]u8{1} ** 32); const pubkey = Pubkey.fromPublicKey(&keypair.public_key); var rng = std.rand.DefaultPrng.init(0); @@ -1778,7 +1773,7 @@ test "gossip.data: test sig verify duplicateShreds" { try std.testing.expect(try value.verify(pubkey)); } -test "gossip.data: test sanitize GossipData" { +test "sanitize GossipData" { var rng = std.rand.DefaultPrng.init(0); const rand = rng.random(); @@ -1788,7 +1783,7 @@ test "gossip.data: test sanitize GossipData" { } } -test "gossip.data: test SignedGossipData label() and id() methods" { +test "SignedGossipData label() and id() methods" { const kp_bytes = [_]u8{1} ** 32; var kp = try KeyPair.create(kp_bytes); const pk = kp.public_key; @@ -1805,7 +1800,7 @@ test "gossip.data: test SignedGossipData label() and id() methods" { try std.testing.expect(value.label().LegacyContactInfo.equals(&id)); } -test "gossip.data: pubkey matches rust" { +test "pubkey matches rust" { const kp_bytes = [_]u8{1} ** 32; const kp = try KeyPair.create(kp_bytes); const pk = kp.public_key; @@ -1823,7 +1818,7 @@ test "gossip.data: pubkey matches rust" { try std.testing.expectEqual(id, out); } -test "gossip.data: contact info serialization matches rust" { +test "contact info serialization matches rust" { const kp_bytes = [_]u8{1} ** 32; const kp = try KeyPair.create(kp_bytes); const pk = kp.public_key; @@ -1853,7 +1848,7 @@ test "gossip.data: contact info serialization matches rust" { try std.testing.expectEqualSlices(u8, bytes[0..bytes.len], &contact_info_rust); } -test "gossip.data: test RestartHeaviestFork serialization matches rust" { +test "RestartHeaviestFork serialization matches rust" { var rust_bytes = [_]u8{ 82, 182, 93, 119, 193, 123, 4, 235, 68, 64, 82, 233, 51, 34, 232, 123, 245, 237, 236, 142, 251, 1, 123, 124, 26, 40, 219, 84, 165, 116, 208, 63, 19, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 20, 0 }; const x = RestartHeaviestFork{ @@ -1870,7 +1865,7 @@ test "gossip.data: test RestartHeaviestFork serialization matches rust" { try std.testing.expectEqualSlices(u8, bytes[0..bytes.len], rust_bytes[0..bytes.len]); } -test "gossip.data: test RestartLastVotedForkSlots serialization matches rust" { +test "RestartLastVotedForkSlots serialization matches rust" { var rust_bytes = [_]u8{ 82, 182, 93, 119, 193, 123, 4, 235, 68, 64, 82, 233, 51, 34, 232, 123, 245, 237, 236, 142, 251, 1, 123, 124, 26, 40, 219, 84, 165, 116, 208, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 16, 0, 0, 0, 0, 0, 0, 0, 255, 255, 239, 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; var x = try DynamicArrayBitSet(u8).initFull(std.testing.allocator, 128); @@ -1896,7 +1891,7 @@ test "gossip.data: test RestartLastVotedForkSlots serialization matches rust" { try std.testing.expectEqualSlices(u8, bytes[0..bytes.len], rust_bytes[0..bytes.len]); } -test "gossip.data: gossip data serialization matches rust" { +test "gossip data serialization matches rust" { const kp_bytes = [_]u8{1} ** 32; const kp = try KeyPair.create(kp_bytes); const pk = kp.public_key; @@ -1928,7 +1923,7 @@ test "gossip.data: gossip data serialization matches rust" { try std.testing.expectEqualSlices(u8, bytes[0..bytes.len], rust_gossip_data[0..bytes.len]); } -test "gossip.data: random gossip data" { +test "random gossip data" { const seed: u64 = @intCast(std.time.milliTimestamp()); var rand = std.rand.DefaultPrng.init(seed); const rng = rand.random(); @@ -1962,7 +1957,7 @@ test "gossip.data: random gossip data" { } } -test "gossip.data: LegacyContactInfo <-> ContactInfo roundtrip" { +test "LegacyContactInfo <-> ContactInfo roundtrip" { const seed: u64 = @intCast(std.time.milliTimestamp()); var rand = std.rand.DefaultPrng.init(seed); const rng = rand.random(); @@ -1975,7 +1970,7 @@ test "gossip.data: LegacyContactInfo <-> ContactInfo roundtrip" { try std.testing.expect(std.meta.eql(start, end)); } -test "gossip.data: sanitize valid ContactInfo works" { +test "sanitize valid ContactInfo works" { var rand = std.rand.DefaultPrng.init(871329); const rng = rand.random(); const info = try ContactInfo.random(std.testing.allocator, rng, Pubkey.random(rng), 100, 123, 246); @@ -1984,7 +1979,7 @@ test "gossip.data: sanitize valid ContactInfo works" { try data.sanitize(); } -test "gossip.data: sanitize invalid ContactInfo has error" { +test "sanitize invalid ContactInfo has error" { var rand = std.rand.DefaultPrng.init(3414214); const rng = rand.random(); const info = try ContactInfo.random(std.testing.allocator, rng, Pubkey.random(rng), 1_000_000_000_000_000, 123, 246); @@ -1993,7 +1988,7 @@ test "gossip.data: sanitize invalid ContactInfo has error" { if (data.sanitize()) |_| return error.ExpectedError else |_| {} } -test "gossip.data: sanitize valid NodeInstance works" { +test "sanitize valid NodeInstance works" { var rand = std.rand.DefaultPrng.init(23523413); const rng = rand.random(); const instance = NodeInstance.random(rng); @@ -2001,7 +1996,7 @@ test "gossip.data: sanitize valid NodeInstance works" { try data.sanitize(); } -test "gossip.data: sanitize invalid NodeInstance has error" { +test "sanitize invalid NodeInstance has error" { var rand = std.rand.DefaultPrng.init(524145234); const rng = rand.random(); var instance = NodeInstance.random(rng); @@ -2010,7 +2005,7 @@ test "gossip.data: sanitize invalid NodeInstance has error" { if (data.sanitize()) |_| return error.ExpectedError else |_| {} } -test "gossip.data: sanitize valid SnapshotHashes works" { +test "sanitize valid SnapshotHashes works" { var rand = std.rand.DefaultPrng.init(23523413); const rng = rand.random(); var instance = SnapshotHashes.random(rng); @@ -2019,7 +2014,7 @@ test "gossip.data: sanitize valid SnapshotHashes works" { try data.sanitize(); } -test "gossip.data: sanitize invalid SnapshotHashes full slot has error" { +test "sanitize invalid SnapshotHashes full slot has error" { var rand = std.rand.DefaultPrng.init(524145234); const rng = rand.random(); var instance = SnapshotHashes.random(rng); @@ -2028,7 +2023,7 @@ test "gossip.data: sanitize invalid SnapshotHashes full slot has error" { if (data.sanitize()) |_| return error.ExpectedError else |_| {} } -test "gossip.data: sanitize invalid SnapshotHashes incremental slot has error" { +test "sanitize invalid SnapshotHashes incremental slot has error" { var rand = std.rand.DefaultPrng.init(524145234); const rng = rand.random(); var incremental: [1]SlotAndHash = .{.{ .slot = 1_000_000_000_487_283, .hash = Hash.default() }}; @@ -2038,7 +2033,7 @@ test "gossip.data: sanitize invalid SnapshotHashes incremental slot has error" { if (data.sanitize()) |_| return error.ExpectedError else |_| {} } -test "gossip.data: sanitize SnapshotHashes full > incremental has error" { +test "sanitize SnapshotHashes full > incremental has error" { var rand = std.rand.DefaultPrng.init(524145234); const rng = rand.random(); var incremental: [1]SlotAndHash = .{.{ .slot = 1, .hash = Hash.default() }}; diff --git a/src/gossip/dump_service.zig b/src/gossip/dump_service.zig index 3e462cf00..b0bdc82d7 100644 --- a/src/gossip/dump_service.zig +++ b/src/gossip/dump_service.zig @@ -1,11 +1,12 @@ const std = @import("std"); -const SignedGossipData = @import("../gossip/data.zig").SignedGossipData; -const GossipTable = @import("../gossip/table.zig").GossipTable; -const Logger = @import("../trace/log.zig").Logger; -const RwMux = @import("../sync/mux.zig").RwMux; +const sig = @import("../sig.zig"); const Allocator = std.mem.Allocator; const Atomic = std.atomic.Value; +const SignedGossipData = sig.gossip.data.SignedGossipData; +const GossipTable = sig.gossip.table.GossipTable; +const Logger = sig.trace.log.Logger; +const RwMux = sig.sync.mux.RwMux; pub const GossipDumpService = struct { allocator: Allocator, diff --git a/src/gossip/fuzz_service.zig b/src/gossip/fuzz_service.zig index cef6a6bf7..8e2562a9b 100644 --- a/src/gossip/fuzz_service.zig +++ b/src/gossip/fuzz_service.zig @@ -1,11 +1,12 @@ //! to use the fuzzer run the following command: //! ./zig-out/bin/fuzz ? //! to stop the fuzzer write any input to stdin and press enter - const std = @import("std"); const sig = @import("../sig.zig"); + const bincode = sig.bincode; +const EndPoint = @import("zig-network").EndPoint; const GossipService = sig.gossip.service.GossipService; const ChunkType = sig.gossip.service.ChunkType; const LegacyContactInfo = sig.gossip.data.LegacyContactInfo; @@ -20,16 +21,14 @@ const SocketAddr = sig.net.net.SocketAddr; const Pubkey = sig.core.pubkey.Pubkey; const Bloom = sig.bloom.bloom.Bloom; const Packet = sig.net.packet.Packet; -const PACKET_DATA_SIZE = sig.net.packet.PACKET_DATA_SIZE; const Hash = sig.core.hash.Hash; -const EndPoint = @import("zig-network").EndPoint; const KeyPair = std.crypto.sign.Ed25519.KeyPair; const AtomicBool = std.atomic.Value(bool); +const Duration = sig.time.Duration; const gossipDataToPackets = sig.gossip.service.gossipDataToPackets; -const Duration = sig.time.Duration; - +const PACKET_DATA_SIZE = sig.net.packet.PACKET_DATA_SIZE; const SLEEP_TIME = Duration.zero(); // const SLEEP_TIME = Duration.fromMillis(10); // const SLEEP_TIME = Duration.fromSecs(10); diff --git a/src/gossip/fuzz_table.zig b/src/gossip/fuzz_table.zig index fee3d07ba..7935d1cb1 100644 --- a/src/gossip/fuzz_table.zig +++ b/src/gossip/fuzz_table.zig @@ -9,12 +9,10 @@ const ContactInfo = sig.gossip.data.ContactInfo; const Logger = sig.trace.log.Logger; const Pubkey = sig.core.pubkey.Pubkey; const GossipTable = sig.gossip.GossipTable; - const SignedGossipData = sig.gossip.data.SignedGossipData; const GossipData = sig.gossip.data.GossipData; const GossipKey = sig.gossip.data.GossipKey; const Signature = sig.core.Signature; - const ThreadPool = sig.sync.thread_pool.ThreadPool; const Duration = sig.time.Duration; diff --git a/src/gossip/lib.zig b/src/gossip/lib.zig index e6b4ee9c2..ddbb161f7 100644 --- a/src/gossip/lib.zig +++ b/src/gossip/lib.zig @@ -18,6 +18,4 @@ pub const SignedGossipData = data.SignedGossipData; pub const LowestSlot = data.LowestSlot; pub const Ping = ping_pong.Ping; pub const Pong = ping_pong.Pong; - -pub const getWallclockMs = data.getWallclockMs; pub const SocketTag = data.SocketTag; diff --git a/src/gossip/message.zig b/src/gossip/message.zig index a0e711a5e..f01ef4d9c 100644 --- a/src/gossip/message.zig +++ b/src/gossip/message.zig @@ -1,25 +1,24 @@ const std = @import("std"); -const Pubkey = @import("../core/pubkey.zig").Pubkey; -const Signature = @import("../core/signature.zig").Signature; -const bincode = @import("../bincode/bincode.zig"); -const SocketAddr = @import("../net/net.zig").SocketAddr; +const sig = @import("../sig.zig"); -const _gossip_data = @import("data.zig"); -const SignedGossipData = _gossip_data.SignedGossipData; -const GossipData = _gossip_data.GossipData; -const LegacyContactInfo = _gossip_data.LegacyContactInfo; -const getWallclockMs = _gossip_data.getWallclockMs; - -const GossipPullFilter = @import("pull_request.zig").GossipPullFilter; -const PACKET_DATA_SIZE = @import("../net/packet.zig").PACKET_DATA_SIZE; +const bincode = sig.bincode; +const testing = std.testing; +const Pubkey = sig.core.Pubkey; +const Signature = sig.core.Signature; +const SocketAddr = sig.net.SocketAddr; +const SignedGossipData = sig.gossip.data.SignedGossipData; +const GossipData = sig.gossip.data.GossipData; +const LegacyContactInfo = sig.gossip.data.LegacyContactInfo; +const GossipPullFilter = sig.gossip.pull_request.GossipPullFilter; +const Ping = sig.gossip.ping_pong.Ping; +const Pong = sig.gossip.ping_pong.Pong; const DefaultPrng = std.rand.DefaultPrng; const KeyPair = std.crypto.sign.Ed25519.KeyPair; -const testing = std.testing; -const Ping = @import("ping_pong.zig").Ping; -const Pong = @import("ping_pong.zig").Pong; +const getWallclockMs = sig.time.getWallclockMs; +const PACKET_DATA_SIZE = sig.net.packet.PACKET_DATA_SIZE; pub const MAX_WALLCLOCK: u64 = 1_000_000_000_000_000; /// Analogous to [Protocol](https://github.com/solana-labs/solana/blob/e0203f22dc83cb792fa97f91dbe6e924cbd08af1/gossip/src/cluster_info.rs#L268) @@ -183,8 +182,8 @@ pub const PruneData = struct { .wallclock = self.wallclock, }; const out = try bincode.writeToSlice(&slice, signable_data, bincode.Params{}); - var sig = try keypair.sign(out, null); - self.signature.data = sig.toBytes(); + var signature = try keypair.sign(out, null); + self.signature.data = signature.toBytes(); } pub fn verify(self: *const PruneData) !void { @@ -204,7 +203,7 @@ pub const PruneData = struct { }; test "gossip.message: push message serialization is predictable" { - var rng = DefaultPrng.init(_gossip_data.getWallclockMs()); + var rng = DefaultPrng.init(getWallclockMs()); const pubkey = Pubkey.random(rng.random()); var values = std.ArrayList(SignedGossipData).init(std.testing.allocator); defer values.deinit(); @@ -230,7 +229,7 @@ test "gossip.message: test prune data sig verify" { 121, 12, 227, 248, 199, 156, 253, 144, 175, 67, })); - var rng = DefaultPrng.init(_gossip_data.getWallclockMs()); + var rng = DefaultPrng.init(getWallclockMs()); var prune = try PruneData.random(rng.random(), &keypair); try prune.verify(); diff --git a/src/gossip/ping_pong.zig b/src/gossip/ping_pong.zig index 1afdf080c..51edb4854 100644 --- a/src/gossip/ping_pong.zig +++ b/src/gossip/ping_pong.zig @@ -5,7 +5,6 @@ const testing = std.testing; const DefaultPrng = std.rand.DefaultPrng; const KeyPair = std.crypto.sign.Ed25519.KeyPair; - const LruCache = sig.common.lru.LruCache; const Pubkey = sig.core.Pubkey; const Hash = sig.core.Hash; @@ -14,7 +13,7 @@ const ThreadSafeContactInfo = sig.gossip.data.ThreadSafeContactInfo; const SocketAddr = sig.net.SocketAddr; const Duration = sig.time.Duration; -const getWallclockMs = sig.gossip.data.getWallclockMs; +const getWallclockMs = sig.time.getWallclockMs; const PING_TOKEN_SIZE: usize = 32; const PING_PONG_HASH_PREFIX: [16]u8 = .{ @@ -246,7 +245,7 @@ pub const PingCache = struct { } }; -test "gossip.ping_pong: PingCache works" { +test "PingCache works" { var ping_cache = try PingCache.init( testing.allocator, Duration.fromNanos(10_000), @@ -282,7 +281,7 @@ test "gossip.ping_pong: PingCache works" { try testing.expect(ping != null); } -test "gossip.ping_pong: ping signatures match rust" { +test "ping signatures match rust" { var keypair = try KeyPair.fromSecretKey(try std.crypto.sign.Ed25519.SecretKey.fromBytes([_]u8{ 125, 52, 162, 97, 231, 139, 58, 13, 185, 212, 57, 142, 136, 12, 21, 127, 228, 71, 115, 126, 138, 52, 102, 69, 103, 185, 45, 255, 132, 222, 243, 138, 25, 117, 21, 11, diff --git a/src/gossip/pull_request.zig b/src/gossip/pull_request.zig index 145f8e703..190384a49 100644 --- a/src/gossip/pull_request.zig +++ b/src/gossip/pull_request.zig @@ -1,16 +1,17 @@ const std = @import("std"); -const Hash = @import("../core/hash.zig").Hash; -const bincode = @import("../bincode/bincode.zig"); +const sig = @import("../sig.zig"); +const bincode = sig.bincode; + +const Hash = sig.core.Hash; const ArrayList = std.ArrayList; -const Bloom = @import("../bloom/bloom.zig").Bloom; +const Bloom = sig.bloom.Bloom; const KeyPair = std.crypto.sign.Ed25519.KeyPair; -const Pubkey = @import("../core/pubkey.zig").Pubkey; -const exp = std.math.exp; +const Pubkey = sig.core.Pubkey; +const GossipTable = sig.gossip.table.GossipTable; +const SignedGossipData = sig.gossip.data.SignedGossipData; +const RwMux = sig.sync.RwMux; -const GossipTable = @import("table.zig").GossipTable; -const _gossip_data = @import("data.zig"); -const SignedGossipData = _gossip_data.SignedGossipData; -const RwMux = @import("../sync/mux.zig").RwMux; +const exp = std.math.exp; pub const MAX_BLOOM_SIZE: usize = 928; pub const MAX_NUM_PULL_REQUESTS: usize = 20; // labs - 1024; @@ -21,7 +22,7 @@ pub const KEYS: f64 = 8; /// corresponding filters. Note: make sure to call deinit_gossip_filters. pub fn buildGossipPullFilters( alloc: std.mem.Allocator, - rand: std.Random, + rng: std.Random, gossip_table_rw: *RwMux(GossipTable), failed_pull_hashes: *const ArrayList(Hash), bloom_size: usize, @@ -34,7 +35,7 @@ pub fn buildGossipPullFilters( const num_items = gossip_table.len() + gossip_table.purged.len() + failed_pull_hashes.items.len; - var filter_set = try GossipPullFilterSet.init(alloc, rand, num_items, bloom_size); + var filter_set = try GossipPullFilterSet.init(alloc, rng, num_items, bloom_size); errdefer filter_set.deinit(); // add all gossip values @@ -58,7 +59,7 @@ pub fn buildGossipPullFilters( errdefer filter_set.deinit(); // note: filter set is deinit() in this fcn - const filters = try filter_set.consumeForGossipPullFilters(alloc, rand, max_n_filters); + const filters = try filter_set.consumeForGossipPullFilters(alloc, rng, max_n_filters); return filters; } @@ -158,11 +159,16 @@ pub const GossipPullFilterSet = struct { } /// returns a list of GossipPullFilters and consumes Self by calling deinit. - pub fn consumeForGossipPullFilters(self: *Self, alloc: std.mem.Allocator, rand: std.Random, max_size: usize) error{OutOfMemory}!ArrayList(GossipPullFilter) { + pub fn consumeForGossipPullFilters( + self: *Self, + allocator: std.mem.Allocator, + rng: std.Random, + max_size: usize, + ) error{OutOfMemory}!ArrayList(GossipPullFilter) { defer self.deinit(); // ! const set_size = self.len(); - var indexs = try ArrayList(usize).initCapacity(alloc, set_size); + var indexs = try ArrayList(usize).initCapacity(allocator, set_size); defer indexs.deinit(); for (0..set_size) |i| { indexs.appendAssumeCapacity(i); @@ -173,7 +179,7 @@ pub const GossipPullFilterSet = struct { if (!can_consume_all) { // shuffle the indexs - shuffleFirstN(rand, usize, indexs.items, n_filters); + shuffleFirstN(rng, usize, indexs.items, n_filters); // release others for (n_filters..set_size) |i| { @@ -182,7 +188,7 @@ pub const GossipPullFilterSet = struct { } } - var filters = try ArrayList(GossipPullFilter).initCapacity(alloc, n_filters); + var filters = try ArrayList(GossipPullFilter).initCapacity(allocator, n_filters); for (0..n_filters) |i| { const index = indexs.items[i]; @@ -254,10 +260,10 @@ pub fn hashToU64(hash: *const Hash) u64 { return std.mem.readInt(u64, buf, .little); } -const LegacyContactInfo = _gossip_data.LegacyContactInfo; +test "building pull filters" { + const LegacyContactInfo = sig.gossip.data.LegacyContactInfo; + const ThreadPool = sig.sync.ThreadPool; -test "gossip.pull_request: test building filters" { - const ThreadPool = @import("../sync/thread_pool.zig").ThreadPool; var tp = ThreadPool.init(.{}); var gossip_table = try GossipTable.init(std.testing.allocator, &tp); defer gossip_table.deinit(); @@ -311,7 +317,7 @@ test "gossip.pull_request: test building filters" { } } -test "gossip.pull_request: filter set deinits correct" { +test "filter set deinits correct" { var prng = std.Random.Xoshiro256.init(@intCast(std.time.milliTimestamp())); const rand = prng.random(); @@ -335,7 +341,7 @@ test "gossip.pull_request: filter set deinits correct" { try std.testing.expect(x.filter.contains(&hash.data)); } -test "gossip.pull_request: helper functions are correct" { +test "GossipPullFilter helper methods are correct" { { const v = GossipPullFilter.computeMaxItems(100.5, 0.1, 10.0); try std.testing.expectEqual(@as(f64, 16), v); @@ -358,7 +364,7 @@ test "gossip.pull_request: helper functions are correct" { } } -test "gossip.pull_request: gossip filter matches rust bytes" { +test "filter matches rust bytes" { const rust_bytes = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0 }; var filter = GossipPullFilter.init(std.testing.allocator); defer filter.deinit(); diff --git a/src/gossip/pull_response.zig b/src/gossip/pull_response.zig index 155f1fec8..d4db64434 100644 --- a/src/gossip/pull_response.zig +++ b/src/gossip/pull_response.zig @@ -1,26 +1,25 @@ const std = @import("std"); -const Hash = @import("../core/hash.zig").Hash; +const sig = @import("../sig.zig"); + +const Hash = sig.core.Hash; const ArrayList = std.ArrayList; const KeyPair = std.crypto.sign.Ed25519.KeyPair; -const Pubkey = @import("../core/pubkey.zig").Pubkey; - -const RwMux = @import("../sync/mux.zig").RwMux; -const GossipTable = @import("table.zig").GossipTable; -const _gossip_data = @import("data.zig"); -const GossipData = _gossip_data.GossipData; -const SignedGossipData = _gossip_data.SignedGossipData; +const Pubkey = sig.core.Pubkey; +const RwMux = sig.sync.mux.RwMux; +const GossipTable = sig.gossip.table.GossipTable; +const GossipData = sig.gossip.data.GossipData; +const SignedGossipData = sig.gossip.data.SignedGossipData; +const GossipPullFilter = sig.gossip.pull_request.GossipPullFilter; -const _pull_request = @import("pull_request.zig"); -const GossipPullFilter = _pull_request.GossipPullFilter; -const buildGossipPullFilters = _pull_request.buildGossipPullFilters; -const deinitGossipPullFilters = _pull_request.deinitGossipPullFilters; +const buildGossipPullFilters = sig.gossip.pull_request.buildGossipPullFilters; +const deinitGossipPullFilters = sig.gossip.pull_request.deinitGossipPullFilters; pub const GOSSIP_PULL_TIMEOUT_MS: u64 = 15000; pub fn filterSignedGossipDatas( /// It is advised to use a PRNG, and not a true RNG, otherwise /// the runtime of this function may be unbounded. - rand: std.Random, + rng: std.Random, allocator: std.mem.Allocator, gossip_table: *const GossipTable, filter: *const GossipPullFilter, @@ -31,7 +30,7 @@ pub fn filterSignedGossipDatas( return ArrayList(SignedGossipData).init(allocator); } - const jitter = rand.intRangeAtMost(u64, 0, GOSSIP_PULL_TIMEOUT_MS / 4); + const jitter = rng.intRangeAtMost(u64, 0, GOSSIP_PULL_TIMEOUT_MS / 4); const caller_wallclock_with_jitter = caller_wallclock + jitter; var bloom = filter.filter; @@ -69,7 +68,7 @@ pub fn filterSignedGossipDatas( return output; } -const LegacyContactInfo = _gossip_data.LegacyContactInfo; +const LegacyContactInfo = sig.gossip.data.LegacyContactInfo; test "gossip.pull_response: test filtering values works" { const ThreadPool = @import("../sync/thread_pool.zig").ThreadPool; diff --git a/src/gossip/service.zig b/src/gossip/service.zig index 6909ef338..37b39a194 100644 --- a/src/gossip/service.zig +++ b/src/gossip/service.zig @@ -54,7 +54,7 @@ const Duration = sig.time.Duration; const endpointToString = sig.net.endpointToString; const globalRegistry = sig.prometheus.globalRegistry; -const getWallclockMs = sig.gossip.data.getWallclockMs; +const getWallclockMs = sig.time.getWallclockMs; const PACKET_DATA_SIZE = sig.net.packet.PACKET_DATA_SIZE; const UNIQUE_PUBKEY_CAPACITY = sig.gossip.table.UNIQUE_PUBKEY_CAPACITY; @@ -321,10 +321,10 @@ pub const GossipService = struct { self.logger, }); try manager.spawn("gossip verifyPackets", verifyPackets, .{self}); - try manager.spawn("gossip processMessages", processMessages, .{self}); + try manager.spawn("gossip processMessages", processMessages, .{ self, 19 }); if (!params.spy_node) { - try manager.spawn("gossip buildMessages", buildMessages, .{self}); + try manager.spawn("gossip buildMessages", buildMessages, .{ self, 19 }); } try manager.spawn("gossip sendSocket", socket_utils.sendSocket, .{ @@ -471,7 +471,7 @@ pub const GossipService = struct { }; /// main logic for recieving and processing gossip messages. - pub fn processMessages(self: *Self) !void { + pub fn processMessages(self: *Self, seed: u64) !void { var trim_table_timer = try sig.time.Timer.start(); var msg_count: usize = 0; @@ -689,7 +689,7 @@ pub const GossipService = struct { if (pull_requests.items.len > 0) { var x_timer = sig.time.Timer.start() catch unreachable; - self.handleBatchPullRequest(pull_requests) catch |err| { + self.handleBatchPullRequest(pull_requests, seed + msg_count) catch |err| { self.logger.errf("handleBatchPullRequest failed: {}", .{err}); }; const elapsed = x_timer.read().asMillis(); @@ -777,20 +777,22 @@ pub const GossipService = struct { } }; - self.logger.infof("gossip table: dropped {} pubkeys", .{n_pubkeys_dropped}); self.stats.table_pubkeys_dropped.add(n_pubkeys_dropped); } /// main gossip loop for periodically sending new GossipMessagemessages. /// this includes sending push messages, pull requests, and triming old /// gossip data (in the gossip_table, active_set, and failed_pull_hashes). - fn buildMessages(self: *Self) !void { + fn buildMessages(self: *Self, seed: u64) !void { var loop_timer = try sig.time.Timer.start(); var active_set_timer = try sig.time.Timer.start(); var pull_req_timer = try sig.time.Timer.start(); var stats_publish_timer = try sig.time.Timer.start(); var trim_memory_timer = try sig.time.Timer.start(); + var prng = std.rand.DefaultPrng.init(seed); + const rng = prng.random(); + var push_cursor: u64 = 0; var entrypoints_identified = false; var shred_version_assigned = false; @@ -801,11 +803,11 @@ pub const GossipService = struct { if (pull_req_timer.read().asNanos() > PULL_REQUEST_RATE.asNanos()) pull_blk: { defer pull_req_timer.reset(); // this also includes sending ping messages to other peers - const prng_seed: u64 = @intCast(std.time.milliTimestamp()); - var prng = std.Random.Xoshiro256.init(prng_seed); + const now = getWallclockMs(); const packets = self.buildPullRequests( - prng.random(), + rng, pull_request.MAX_BLOOM_SIZE, + now, ) catch |e| { self.logger.errf("failed to generate pull requests: {any}", .{e}); break :pull_blk; @@ -858,9 +860,7 @@ pub const GossipService = struct { try push_msg_queue.append(my_legacy_contact_info_value); } - const prng_seed: u64 = @intCast(std.time.milliTimestamp()); - var prng = std.Random.Xoshiro256.init(prng_seed); - try self.rotateActiveSet(prng.random()); + try self.rotateActiveSet(rng); } // publish metrics @@ -1053,10 +1053,10 @@ pub const GossipService = struct { rand: std.Random, /// the bloomsize of the pull request's filters bloom_size: usize, + now: u64, ) !ArrayList(Packet) { // get nodes from gossip table var buf: [MAX_NUM_PULL_REQUESTS]ThreadSafeContactInfo = undefined; - const now = getWallclockMs(); const peers = try self.getThreadSafeGossipNodes( &buf, MAX_NUM_PULL_REQUESTS, @@ -1178,6 +1178,7 @@ pub const GossipService = struct { output: ArrayList(Packet), output_limit: *std.atomic.Value(i64), output_consumed: std.atomic.Value(bool) = std.atomic.Value(bool).init(false), + seed: u64, task: Task, done: std.atomic.Value(bool) = std.atomic.Value(bool).init(false), @@ -1197,10 +1198,9 @@ pub const GossipService = struct { return; } - const filter_rng_seed: u64 = @intCast(std.time.milliTimestamp()); - var filter_prng = std.Random.Xoshiro256.init(filter_rng_seed); + var rng = std.Random.Xoshiro256.init(self.seed); const response_gossip_values = pull_response.filterSignedGossipDatas( - filter_prng.random(), + rng.random(), self.allocator, self.gossip_table, self.filter, @@ -1239,6 +1239,7 @@ pub const GossipService = struct { fn handleBatchPullRequest( self: *Self, pull_requests: ArrayList(PullRequestMessage), + seed: u64, ) !void { // update the callers // TODO: parallelize this? @@ -1312,6 +1313,7 @@ pub const GossipService = struct { .output = ArrayList(Packet).init(self.allocator), .allocator = self.allocator, .output_limit = &output_limit, + .seed = seed + i, }; // run it @@ -1698,7 +1700,6 @@ pub const GossipService = struct { // - if all nodes have zero stake: epoch duration // - if any other nodes have non-zero stake: GOSSIP_PULL_TIMEOUT_MS (15s) const n_values_removed = try gossip_table.removeOldLabels(now, DEFAULT_EPOCH_DURATION); - self.logger.infof("gossip table: removed {} old labels", .{n_values_removed}); self.stats.table_old_values_removed.add(n_values_removed); self.stats.table_remove_old_values_call_count.inc(); } @@ -2252,10 +2253,12 @@ test "build messages startup and shutdown" { ); defer gossip_service.deinit(); - var build_messages_handle = try Thread.spawn(.{}, GossipService.buildMessages, .{&gossip_service}); + var prng = std.Random.Xoshiro256.init(0); + const rng = prng.random(); + + var build_messages_handle = try Thread.spawn(.{}, GossipService.buildMessages, .{ &gossip_service, 19 }); // add some gossip values to push - var rng = std.rand.DefaultPrng.init(91); var lg = gossip_service.gossip_table_rw.write(); var ping_lock = gossip_service.ping_cache_rw.write(); var ping_cache: *PingCache = ping_lock.mut(); @@ -2265,7 +2268,7 @@ test "build messages startup and shutdown" { for (0..10) |_| { var rand_keypair = try KeyPair.create(null); - var value = try SignedGossipData.randomWithIndex(rng.random(), &rand_keypair, 0); // contact info + var value = try SignedGossipData.randomWithIndex(rng, &rand_keypair, 0); // contact info // make gossip valid value.data.LegacyContactInfo.gossip = SocketAddr.initIpv4(.{ 127, 0, 0, 1 }, 8000); _ = try lg.mut().insert(value, getWallclockMs()); @@ -2634,7 +2637,7 @@ test "handle pull request" { .value = ci, }); - try gossip_service.handleBatchPullRequest(pull_requests); + try gossip_service.handleBatchPullRequest(pull_requests, 19); { const outgoing_packets = gossip_service.packet_outgoing_channel; @@ -2748,9 +2751,9 @@ test "test build prune messages and handle push messages" { try std.testing.expectEqual(prune_data.prunes.len, 10); } -test "test build pull requests" { +test "build pull requests" { const allocator = std.testing.allocator; - var rng = std.rand.DefaultPrng.init(91); + var prng = std.rand.DefaultPrng.init(91); var exit = AtomicBool.init(false); var my_keypair = try KeyPair.create([_]u8{1} ** 32); const my_pubkey = Pubkey.fromPublicKey(&my_keypair.public_key); @@ -2772,6 +2775,7 @@ test "test build pull requests" { defer gossip_service.deinit(); // insert peers to send msgs to + const now = getWallclockMs(); { var ping_lock = gossip_service.ping_cache_rw.write(); var lg = gossip_service.gossip_table_rw.write(); @@ -2781,10 +2785,9 @@ test "test build pull requests" { } var pc: *PingCache = ping_lock.mut(); - const now = getWallclockMs(); for (0..20) |i| { var rando_keypair = try KeyPair.create(null); - var value = try SignedGossipData.randomWithIndex(rng.random(), &rando_keypair, 0); + var value = try SignedGossipData.randomWithIndex(prng.random(), &rando_keypair, 0); value.wallclockPtr().* = now + 10 * i; _ = try lg.mut().insert(value, now + 10 * i); @@ -2792,10 +2795,8 @@ test "test build pull requests" { } } - const maybe_failing_seed: u64 = @intCast(std.time.milliTimestamp()); - var maybe_failing_prng = std.Random.Xoshiro256.init(maybe_failing_seed); - var packets = gossip_service.buildPullRequests(maybe_failing_prng.random(), 2) catch |err| { - std.log.err("\nThe failing seed is: '{d}'\n", .{maybe_failing_seed}); + var packets = gossip_service.buildPullRequests(prng.random(), 2, now) catch |err| { + std.log.err("\nThe failing now time is: '{d}'\n", .{now}); return err; }; defer packets.deinit(); @@ -3107,7 +3108,7 @@ test "process contact info push packet" { var packet_handle = try Thread.spawn( .{}, GossipService.processMessages, - .{&gossip_service}, + .{ &gossip_service, 19 }, ); // send a push message diff --git a/src/gossip/shards.zig b/src/gossip/shards.zig index 390708296..2c3ea334d 100644 --- a/src/gossip/shards.zig +++ b/src/gossip/shards.zig @@ -1,15 +1,13 @@ const std = @import("std"); -const AutoArrayHashMap = std.AutoArrayHashMap; - -const Hash = @import("../core/hash.zig").Hash; - -const _gossip_data = @import("data.zig"); -const SignedGossipData = _gossip_data.SignedGossipData; -const GossipVersionedData = _gossip_data.GossipVersionedData; +const sig = @import("../sig.zig"); +const AutoArrayHashMap = std.AutoArrayHashMap; +const Hash = sig.core.Hash; +const SignedGossipData = sig.gossip.data.SignedGossipData; +const GossipVersionedData = sig.gossip.data.GossipVersionedData; const KeyPair = std.crypto.sign.Ed25519.KeyPair; -const hashToU64 = @import("./pull_request.zig").hashToU64; +const hashToU64 = sig.gossip.pull_request.hashToU64; pub const GOSSIP_SHARDS_BITS: u32 = 12; pub const GOSSIP_SHARDS_LEN: u32 = 1 << GOSSIP_SHARDS_BITS; @@ -104,9 +102,9 @@ pub const GossipTableShards = struct { } }; -const GossipTable = @import("table.zig").GossipTable; +const GossipTable = sig.gossip.table.GossipTable; -test "gossip.gossip_shards: tests GossipTableShards" { +test "GossipTableShards" { var shards = try GossipTableShards.init(std.testing.allocator); defer shards.deinit(); diff --git a/src/gossip/table.zig b/src/gossip/table.zig index 8bace8b9c..7368568ca 100644 --- a/src/gossip/table.zig +++ b/src/gossip/table.zig @@ -23,7 +23,6 @@ const Pubkey = sig.core.Pubkey; const SocketAddr = sig.net.SocketAddr; const PACKET_DATA_SIZE = sig.net.packet.PACKET_DATA_SIZE; - pub const UNIQUE_PUBKEY_CAPACITY: usize = 8_192; pub const MAX_TABLE_SIZE: usize = 100_000; // TODO: better value for this @@ -944,7 +943,7 @@ pub const HashTimeQueue = struct { } }; -test "gossip.table: remove old values" { +test "remove old values" { const keypair = try KeyPair.create([_]u8{1} ** 32); const seed: u64 = @intCast(std.time.milliTimestamp()); @@ -975,7 +974,7 @@ test "gossip.table: remove old values" { try std.testing.expectEqual(table.len(), 0); } -test "gossip.table: insert and remove value" { +test "insert and remove value" { const keypair = try KeyPair.create([_]u8{1} ** 32); const seed: u64 = @intCast(std.time.milliTimestamp()); @@ -995,7 +994,7 @@ test "gossip.table: insert and remove value" { try table.remove(label, 100); } -test "gossip.table: trim pruned values" { +test "trim pruned values" { const keypair = try KeyPair.create([_]u8{1} ** 32); const seed: u64 = @intCast(std.time.milliTimestamp()); @@ -1096,7 +1095,7 @@ test "gossip.HashTimeQueue: trim pruned values" { try std.testing.expectEqual(table.purged.len(), 0); } -test "gossip.table: insert and get" { +test "insert and get" { const keypair = try KeyPair.create([_]u8{1} ** 32); const seed: u64 = @intCast(std.time.milliTimestamp()); @@ -1115,7 +1114,7 @@ test "gossip.table: insert and get" { _ = x; } -test "gossip.table: insert and get contact_info" { +test "insert and get contact_info" { const kp = try KeyPair.create([_]u8{1} ** 32); var id = Pubkey.fromPublicKey(&kp.public_key); diff --git a/src/net/lib.zig b/src/net/lib.zig index 8510fb754..8a2274ac9 100644 --- a/src/net/lib.zig +++ b/src/net/lib.zig @@ -13,3 +13,4 @@ pub const enablePortReuse = net.enablePortReuse; pub const endpointToString = net.endpointToString; pub const SOCKET_TIMEOUT_US = socket_utils.SOCKET_TIMEOUT_US; +pub const PACKET_DATA_SIZE = packet.PACKET_DATA_SIZE; diff --git a/src/net/net.zig b/src/net/net.zig index 72db263d1..9fb327cd4 100644 --- a/src/net/net.zig +++ b/src/net/net.zig @@ -516,7 +516,7 @@ pub fn enablePortReuse(self: *network.Socket, enabled: bool) !void { try setsockopt_fn(self.internal, std.posix.SOL.SOCKET, std.posix.SO.REUSEPORT, std.mem.asBytes(&opt)); } -test "net.net: invalid ipv4 socket parsing" { +test "invalid ipv4 socket parsing" { { const addr = "127.0.0.11234"; const result = SocketAddr.parseIpv4(addr); @@ -529,7 +529,7 @@ test "net.net: invalid ipv4 socket parsing" { } } -test "net.net: valid ipv4 socket parsing" { +test "valid ipv4 socket parsing" { const addr = "127.0.0.1:1234"; const expected_addr = SocketAddr{ .V4 = SocketAddrV4{ .ip = Ipv4Addr.init(127, 0, 0, 1), @@ -539,19 +539,19 @@ test "net.net: valid ipv4 socket parsing" { try std.testing.expectEqual(expected_addr, actual_addr); } -test "net.net: test random" { +test "SocketAddr.random" { var rng = std.rand.DefaultPrng.init(@intCast(std.time.milliTimestamp())); const addr = SocketAddr.random(rng.random()); _ = addr; } -test "net.net: set port works" { +test "set port works" { var sa1 = SocketAddr.initIpv4(.{ 127, 0, 0, 1 }, 1000); sa1.setPort(1001); try std.testing.expectEqual(@as(u16, 1001), sa1.port()); } -test "net.net: parse IPv6 if IPv4 fails" { +test "parse IPv6 if IPv4 fails" { try std.testing.expectError(error.InvalidIp, SocketAddr.parse("[FE38:DCEq:124C:C1A2:BA03:6745:EF1C:683D]:8000")); try std.testing.expectError(error.InvalidIp, SocketAddr.parse("[FE38:DCEE:124C:C1A2:BA03:6745:EF1C:683D]:")); diff --git a/src/rpc/client.zig b/src/rpc/client.zig index edffd9d2d..809a025c6 100644 --- a/src/rpc/client.zig +++ b/src/rpc/client.zig @@ -1326,7 +1326,7 @@ test "pubkey equality works" { try testing.expect(!pubkey1.equals(&pubkeyOther)); } -test "pubkey randome works" { +test "pubkey random works" { const seed: u64 = @intCast(std.time.milliTimestamp()); var rand = std.rand.DefaultPrng.init(seed); const rng = rand.random(); diff --git a/src/time/lib.zig b/src/time/lib.zig index 7572f859b..cbaf7e98a 100644 --- a/src/time/lib.zig +++ b/src/time/lib.zig @@ -1,5 +1,11 @@ +const std = @import("std"); pub const estimate = @import("estimate.zig"); pub const time = @import("time.zig"); pub const Timer = time.Timer; pub const Duration = time.Duration; + +/// returns current timestamp in milliseconds +pub fn getWallclockMs() u64 { + return @intCast(std.time.milliTimestamp()); +}