Skip to content

Commit

Permalink
feat(p2p/messages): add filteradd message (#138)
Browse files Browse the repository at this point in the history
  • Loading branch information
supreme2580 authored Sep 30, 2024
1 parent 6a1f103 commit b71e5d8
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 0 deletions.
83 changes: 83 additions & 0 deletions src/network/protocol/messages/filteradd.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
const std = @import("std");
const protocol = @import("../lib.zig");

/// FilterAddMessage represents the "filteradd" message
///
/// https://developer.bitcoin.org/reference/p2p_networking.html#filteradd
pub const FilterAddMessage = struct {
element: []const u8,

const Self = @This();

pub fn name() *const [12]u8 {
return protocol.CommandNames.FILTERADD ++ [_]u8{0} ** 3;
}

/// Returns the message checksum
pub fn checksum(self: *const Self) [4]u8 {
var digest: [32]u8 = undefined;
std.crypto.hash.sha2.Sha256.hash(self.element, &digest, .{});
std.crypto.hash.sha2.Sha256.hash(&digest, &digest, .{});
return digest[0..4].*;
}

/// Serialize the message as bytes and write them to the Writer.
pub fn serializeToWriter(self: *const Self, w: anytype) !void {
comptime {
if (!std.meta.hasFn(@TypeOf(w), "writeAll")) @compileError("Expects w to have fn 'writeAll'.");
}
try w.writeAll(self.element);
}

/// Serialize a message as bytes and return them.
pub fn serialize(self: *const Self, allocator: std.mem.Allocator) ![]u8 {
const serialized_len = self.hintSerializedLen();
const ret = try allocator.alloc(u8, serialized_len);
errdefer allocator.free(ret);
try self.serializeToSlice(ret);
return ret;
}

/// Serialize a message as bytes and write them to the buffer.
pub fn serializeToSlice(self: *const Self, buffer: []u8) !void {
var fbs = std.io.fixedBufferStream(buffer);
try self.serializeToWriter(fbs.writer());
}

pub fn deserializeReader(allocator: std.mem.Allocator, r: anytype) !Self {
comptime {
if (!std.meta.hasFn(@TypeOf(r), "readAllAlloc")) @compileError("Expects r to have fn 'readAllAlloc'.");
}
const element = try r.readAllAlloc(allocator, 520);
return Self{ .element = element };
}

pub fn deserializeSlice(allocator: std.mem.Allocator, bytes: []const u8) !Self {
var fbs = std.io.fixedBufferStream(bytes);
return try Self.deserializeReader(allocator, fbs.reader());
}

pub fn hintSerializedLen(self: *const Self) usize {
return self.element.len;
}

pub fn deinit(self: *const Self, allocator: std.mem.Allocator) void {
allocator.free(self.element);
}
};

// TESTS
test "ok_fullflow_filteradd_message" {
const allocator = std.testing.allocator;

const element = "test_element";
var msg = FilterAddMessage{ .element = element };

const payload = try msg.serialize(allocator);
defer allocator.free(payload);

var deserialized_msg = try FilterAddMessage.deserializeSlice(allocator, payload);
defer deserialized_msg.deinit(allocator);

try std.testing.expectEqualSlices(u8, element, deserialized_msg.element);
}
7 changes: 7 additions & 0 deletions src/network/protocol/messages/lib.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub const MerkleBlockMessage = @import("merkleblock.zig").MerkleBlockMessage;
pub const FeeFilterMessage = @import("feefilter.zig").FeeFilterMessage;
pub const SendCmpctMessage = @import("sendcmpct.zig").SendCmpctMessage;
pub const FilterClearMessage = @import("filterclear.zig").FilterClearMessage;
pub const FilterAddMessage = @import("filteradd.zig").FilterAddMessage;

pub const MessageTypes = enum {
version,
Expand All @@ -23,6 +24,7 @@ pub const MessageTypes = enum {
sendcmpct,
feefilter,
filterclear,
filteradd,
};

pub const Message = union(MessageTypes) {
Expand All @@ -37,6 +39,7 @@ pub const Message = union(MessageTypes) {
sendcmpct: SendCmpctMessage,
feefilter: FeeFilterMessage,
filterclear: FilterClearMessage,
filteradd: FilterAddMessage,

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

Expand All @@ -67,6 +71,7 @@ pub const Message = union(MessageTypes) {
.sendcmpct => {},
.feefilter => {},
.filterclear => {},
.filteradd => |m| m.deinit(allocator),
}
}

Expand All @@ -83,6 +88,7 @@ pub const Message = union(MessageTypes) {
.sendcmpct => |m| m.checksum(),
.feefilter => |m| m.checksum(),
.filterclear => |m| m.checksum(),
.filteradd => |m| m.checksum(),
};
}

Expand All @@ -99,6 +105,7 @@ pub const Message = union(MessageTypes) {
.sendcmpct => |m| m.hintSerializedLen(),
.feefilter => |m| m.hintSerializedLen(),
.filterclear => |m| m.hintSerializedLen(),
.filteradd => |m| m.hintSerializedLen(),
};
}
};
2 changes: 2 additions & 0 deletions src/network/wire/lib.zig
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ pub fn receiveMessage(
protocol.messages.Message{ .sendcmpct = try protocol.messages.SendCmpctMessage.deserializeReader(allocator, r) }
else if (std.mem.eql(u8, &command, protocol.messages.FilterClearMessage.name()))
protocol.messages.Message{ .filterclear = try protocol.messages.FilterClearMessage.deserializeReader(allocator, r) }
else if (std.mem.eql(u8, &command, protocol.messages.FilterAddMessage.name()))
protocol.messages.Message{ .filteradd = try protocol.messages.FilterAddMessage.deserializeReader(allocator, r) }
else {
try r.skipBytes(payload_len, .{}); // Purge the wire
return error.UnknownMessage;
Expand Down

0 comments on commit b71e5d8

Please sign in to comment.