Skip to content

Commit

Permalink
feat(p2p/messages): add sendheaders (#146)
Browse files Browse the repository at this point in the history
  • Loading branch information
bloomingpeach authored Oct 1, 2024
1 parent 0a16c5a commit 3e2c745
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/network/protocol/messages/lib.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub const SendCmpctMessage = @import("sendcmpct.zig").SendCmpctMessage;
pub const FilterClearMessage = @import("filterclear.zig").FilterClearMessage;
pub const FilterAddMessage = @import("filteradd.zig").FilterAddMessage;
pub const NotFoundMessage = @import("notfound.zig").NotFoundMessage;
pub const SendHeadersMessage = @import("sendheaders.zig").SendHeadersMessage;

pub const InventoryVector = struct {
type: u32,
Expand Down Expand Up @@ -57,6 +58,7 @@ pub const MessageTypes = enum {
filterclear,
filteradd,
notfound,
sendheaders,
};

pub const Message = union(MessageTypes) {
Expand All @@ -73,6 +75,7 @@ pub const Message = union(MessageTypes) {
filterclear: FilterClearMessage,
filteradd: FilterAddMessage,
notfound: NotFoundMessage,
sendheaders: SendHeadersMessage,

pub fn name(self: Message) *const [12]u8 {
return switch (self) {
Expand All @@ -89,6 +92,7 @@ pub const Message = union(MessageTypes) {
.filterclear => |m| @TypeOf(m).name(),
.filteradd => |m| @TypeOf(m).name(),
.notfound => |m| @TypeOf(m).name(),
.sendheaders => |m| @TypeOf(m).name(),
};
}

Expand All @@ -107,6 +111,7 @@ pub const Message = union(MessageTypes) {
.filterclear => {},
.filteradd => |m| m.deinit(allocator),
.notfound => {},
.sendheaders => {},
}
}

Expand All @@ -125,6 +130,7 @@ pub const Message = union(MessageTypes) {
.filterclear => |m| m.checksum(),
.filteradd => |m| m.checksum(),
.notfound => |m| m.checksum(),
.sendheaders => |m| m.checksum(),
};
}

Expand All @@ -143,6 +149,7 @@ pub const Message = union(MessageTypes) {
.filterclear => |m| m.hintSerializedLen(),
.filteradd => |m| m.hintSerializedLen(),
.notfound => |m| m.hintSerializedLen(),
.sendheaders => |m| m.hintSerializedLen(),
};
}
};
59 changes: 59 additions & 0 deletions src/network/protocol/messages/sendheaders.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
const std = @import("std");
const protocol = @import("../lib.zig");

/// SendHeaders represents the "getaddr" message
///
/// https://developer.bitcoin.org/reference/p2p_networking.html#sendheaders
pub const SendHeadersMessage = struct {
// sendheaders message do not contain any payload, thus there is no field
const Self = @This();

pub fn new() Self {
return .{};
}

pub fn name() *const [12]u8 {
return protocol.CommandNames.SENDHEADERS;
}

pub fn checksum(self: Self) [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 Self, allocator: std.mem.Allocator) ![]u8 {
_ = self;
_ = allocator;
return &.{};
}

pub fn deserializeReader(allocator: std.mem.Allocator, r: anytype) !Self {
_ = allocator;
_ = r;
return SendHeadersMessage{};
}

pub fn hintSerializedLen(self: Self) usize {
_ = self;
return 0;
}
};

// TESTS

test "ok_full_flow_SendHeaders" {
const allocator = std.testing.allocator;

{
const msg = SendHeadersMessage{};

const payload = try msg.serialize(allocator);
defer allocator.free(payload);
const deserialized_msg = try SendHeadersMessage.deserializeReader(allocator, payload);
_ = deserialized_msg;

try std.testing.expect(payload.len == 0);
}
}
28 changes: 28 additions & 0 deletions src/network/wire/lib.zig
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ pub fn receiveMessage(
protocol.messages.Message{ .notfound = try protocol.messages.NotFoundMessage.deserializeReader(allocator, r) }
else if (std.mem.eql(u8, &command, protocol.messages.FeeFilterMessage.name()))
protocol.messages.Message{ .feefilter = try protocol.messages.FeeFilterMessage.deserializeReader(allocator, r) }
else if (std.mem.eql(u8, &command, protocol.messages.SendHeadersMessage.name()))
protocol.messages.Message{ .sendheaders = try protocol.messages.SendHeadersMessage.deserializeReader(allocator, r) }
else {
try r.skipBytes(payload_len, .{}); // Purge the wire
return error.UnknownMessage;
Expand Down Expand Up @@ -399,6 +401,32 @@ test "ok_send_pong_message" {
}
}

test "ok_send_sendheaders_message" {
const Config = @import("../../config/config.zig").Config;
const ArrayList = std.ArrayList;
const test_allocator = std.testing.allocator;
const SendHeadersMessage = protocol.messages.SendHeadersMessage;

var list: std.ArrayListAligned(u8, null) = ArrayList(u8).init(test_allocator);
defer list.deinit();

const message = SendHeadersMessage.new();

const received_message = try write_and_read_message(
test_allocator,
&list,
Config.BitcoinNetworkId.MAINNET,
Config.PROTOCOL_VERSION,
message,
) orelse unreachable;
defer received_message.deinit(test_allocator);

switch (received_message) {
.sendheaders => {},
else => unreachable,
}
}

test "ko_receive_invalid_payload_length" {
const Config = @import("../../config/config.zig").Config;
const ArrayList = std.ArrayList;
Expand Down

0 comments on commit 3e2c745

Please sign in to comment.