diff --git a/src/network/protocol/messages/getaddr.zig b/src/network/protocol/messages/getaddr.zig new file mode 100644 index 0000000..3d842b5 --- /dev/null +++ b/src/network/protocol/messages/getaddr.zig @@ -0,0 +1,62 @@ +const std = @import("std"); +const native_endian = @import("builtin").target.cpu.arch.endian(); +const protocol = @import("../lib.zig"); + +const ServiceFlags = protocol.ServiceFlags; + +const Endian = std.builtin.Endian; +const Sha256 = std.crypto.hash.sha2.Sha256; + +const CompactSizeUint = @import("bitcoin-primitives").types.CompatSizeUint; + +/// GetaddrMessage represents the "getaddr" message +/// +/// https://developer.bitcoin.org/reference/p2p_networking.html#getaddr +pub const GetaddrMessage = struct { + // getaddr message do not contain any payload, thus there is no field + + pub inline fn name() *const [12]u8 { + return protocol.CommandNames.GETADDR ++ [_]u8{0} ** 5; + } + + pub fn checksum(self: GetaddrMessage) [4]u8 { + _ = self; + // If payload is empty, the checksum is always 0x5df6e0e2 (SHA256(SHA256(""))) + return [4]u8{ 0x5d, 0xf6, 0xe0, 0xe2 }; + } + + /// Serialize a message as bytes and return them. + pub fn serialize(self: *const GetaddrMessage, allocator: std.mem.Allocator) ![]u8 { + _ = self; + _ = allocator; + return &.{}; + } + + pub fn deserializeReader(allocator: std.mem.Allocator, r: anytype) !GetaddrMessage { + _ = allocator; + _ = r; + return GetaddrMessage{}; + } + + pub fn hintSerializedLen(self: GetaddrMessage) usize { + _ = self; + return 0; + } +}; + +// TESTS + +test "ok_full_flow_GetaddrMessage" { + const allocator = std.testing.allocator; + + { + const msg = GetaddrMessage{}; + + const payload = try msg.serialize(allocator); + defer allocator.free(payload); + const deserialized_msg = try GetaddrMessage.deserializeReader(allocator, payload); + _ = deserialized_msg; + + try std.testing.expect(payload.len == 0); + } +} diff --git a/src/network/protocol/messages/lib.zig b/src/network/protocol/messages/lib.zig index dd8dd39..0e5dcf0 100644 --- a/src/network/protocol/messages/lib.zig +++ b/src/network/protocol/messages/lib.zig @@ -1,23 +1,27 @@ const std = @import("std"); pub const VersionMessage = @import("version.zig").VersionMessage; pub const VerackMessage = @import("verack.zig").VerackMessage; +pub const GetaddrMessage = @import("getaddr.zig").GetaddrMessage; -pub const MessageTypes = enum { Version, Verack }; +pub const MessageTypes = enum { Version, Verack, Getaddr }; pub const Message = union(MessageTypes) { Version: VersionMessage, Verack: VerackMessage, + Getaddr: GetaddrMessage, pub fn deinit(self: Message, allocator: std.mem.Allocator) void { switch (self) { .Version => |m| m.deinit(allocator), .Verack => {}, + .Getaddr => {}, } } pub fn checksum(self: Message) [4]u8 { return switch (self) { .Version => |m| m.checksum(), .Verack => |m| m.checksum(), + .Getaddr => |m| m.checksum(), }; } @@ -25,6 +29,7 @@ pub const Message = union(MessageTypes) { return switch (self) { .Version => |m| m.hintSerializedLen(), .Verack => |m| m.hintSerializedLen(), + .Getaddr => |m| m.hintSerializedLen(), }; } }; diff --git a/src/network/wire/lib.zig b/src/network/wire/lib.zig index 578f5c4..866f2d7 100644 --- a/src/network/wire/lib.zig +++ b/src/network/wire/lib.zig @@ -76,10 +76,12 @@ pub fn receiveMessage(allocator: std.mem.Allocator, r: anytype) !protocol.messag const checksum = try r.readBytesNoEof(4); // Read payload - const message: protocol.messages.Message = if (std.mem.eql(u8, &command, protocol.messages.VersionMessage.name())) - protocol.messages.Message{ .Version = try protocol.messages.VersionMessage.deserializeReader(allocator, r)} + const message: protocol.messages.Message = if (std.mem.eql(u8, &command, protocol.messages.VersionMessage.name())) + protocol.messages.Message{ .Version = try protocol.messages.VersionMessage.deserializeReader(allocator, r) } else if (std.mem.eql(u8, &command, protocol.messages.VerackMessage.name())) - protocol.messages.Message{ .Verack = try protocol.messages.VerackMessage.deserializeReader(allocator, r)} + protocol.messages.Message{ .Verack = try protocol.messages.VerackMessage.deserializeReader(allocator, r) } + else if (std.mem.eql(u8, &command, protocol.messages.GetaddrMessage.name())) + protocol.messages.Message{ .Getaddr = try protocol.messages.GetaddrMessage.deserializeReader(allocator, r) } else return error.InvalidCommand; errdefer message.deinit(allocator); @@ -133,6 +135,7 @@ test "ok_send_version_message" { switch (received_message) { .Version => |rm| try std.testing.expect(message.eql(&rm)), .Verack => unreachable, + .Getaddr => unreachable, } } @@ -157,6 +160,7 @@ test "ok_send_verack_message" { switch (received_message) { .Verack => {}, .Version => unreachable, + .Getaddr => unreachable, } }