Skip to content

Commit

Permalink
feat(p2p/messages): add feefilter msg (#133)
Browse files Browse the repository at this point in the history
  • Loading branch information
supreme2580 authored Sep 27, 2024
1 parent 74586df commit 698dffd
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/network/peer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ pub const Peer = struct {
switch (message) {
// We only received those during handshake, seeing them again is an error
.version, .verack => self.should_listen = false,
.feefilter => |feefilter_message| {
std.log.info("Received feefilter message with feerate: {}", .{feefilter_message.feerate});
// TODO: Implement logic to filter transactions based on the received feerate
},
// TODO: handle other messages correctly
else => |m| {
std.log.info("Peer {any} sent a `{s}` message", .{ self.address, m.name() });
Expand Down
98 changes: 98 additions & 0 deletions src/network/protocol/messages/feefilter.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
const std = @import("std");
const protocol = @import("../lib.zig");
const Sha256 = std.crypto.hash.sha2.Sha256;

/// FeeFilterMessage represents the "feefilter" message
///
/// https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki
pub const FeeFilterMessage = struct {
feerate: u64,

const Self = @This();

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

/// Returns the message checksum
///
/// Computed as `Sha256(Sha256(self.serialize()))[0..4]`
pub fn checksum(self: *const Self) [4]u8 {
var digest: [32]u8 = undefined;
var hasher = Sha256.init(.{});
const writer = hasher.writer();
self.serializeToWriter(writer) catch unreachable; // Sha256.write is infallible
hasher.final(&digest);

Sha256.hash(&digest, &digest, .{});

return digest[0..4].*;
}

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

/// Serialize the message as bytes and write them to the Writer.
pub fn serializeToWriter(self: *const Self, w: anytype) !void {
try w.writeInt(u64, self.feerate, .little);
}

/// 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;
}

/// Deserialize a Reader bytes as a `FeeFilterMessage`
pub fn deserializeReader(_: std.mem.Allocator, r: anytype) !Self {
comptime {
if (!std.meta.hasFn(@TypeOf(r), "readInt")) @compileError("Expects r to have fn 'readInt'.");
}

var fm: Self = undefined;
fm.feerate = try r.readInt(u64, .little);
return fm;
}

/// Deserialize bytes into a `FeeFilterMessage`
pub fn deserializeSlice(allocator: std.mem.Allocator, bytes: []const u8) !Self {
var fbs = std.io.fixedBufferStream(bytes);
const reader = fbs.reader();

return try Self.deserializeReader(allocator, reader);
}

pub fn hintSerializedLen(_: *const Self) usize {
return 8; // feerate is u64 (8 bytes)
}

pub fn new(feerate: u64) Self {
return .{
.feerate = feerate,
};
}
};

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

{
const msg = FeeFilterMessage.new(48508);
const payload = try msg.serialize(allocator);
defer allocator.free(payload);
const deserialized_msg = try FeeFilterMessage.deserializeSlice(allocator, payload);
try std.testing.expectEqual(msg.feerate, deserialized_msg.feerate);
}
}
7 changes: 7 additions & 0 deletions src/network/protocol/messages/lib.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub const GetaddrMessage = @import("getaddr.zig").GetaddrMessage;
pub const GetblocksMessage = @import("getblocks.zig").GetblocksMessage;
pub const PingMessage = @import("ping.zig").PingMessage;
pub const PongMessage = @import("pong.zig").PongMessage;
pub const FeeFilterMessage = @import("feefilter.zig").FeeFilterMessage;

pub const MessageTypes = enum {
version,
Expand All @@ -15,6 +16,7 @@ pub const MessageTypes = enum {
getblocks,
ping,
pong,
feefilter,
};

pub const Message = union(MessageTypes) {
Expand All @@ -25,6 +27,7 @@ pub const Message = union(MessageTypes) {
getblocks: GetblocksMessage,
ping: PingMessage,
pong: PongMessage,
feefilter: FeeFilterMessage,

pub fn name(self: Message) *const [12]u8 {
return switch (self) {
Expand All @@ -35,6 +38,7 @@ pub const Message = union(MessageTypes) {
.getblocks => |m| @TypeOf(m).name(),
.ping => |m| @TypeOf(m).name(),
.pong => |m| @TypeOf(m).name(),
.feefilter => |m| @TypeOf(m).name(),
};
}

Expand All @@ -47,6 +51,7 @@ pub const Message = union(MessageTypes) {
.getblocks => |m| m.deinit(allocator),
.ping => {},
.pong => {},
.feefilter => {},
}
}
pub fn checksum(self: Message) [4]u8 {
Expand All @@ -58,6 +63,7 @@ pub const Message = union(MessageTypes) {
.getblocks => |m| m.checksum(),
.ping => |m| m.checksum(),
.pong => |m| m.checksum(),
.feefilter => |m| m.checksum(),
};
}

Expand All @@ -70,6 +76,7 @@ pub const Message = union(MessageTypes) {
.getblocks => |m| m.hintSerializedLen(),
.ping => |m| m.hintSerializedLen(),
.pong => |m| m.hintSerializedLen(),
.feefilter => |m| m.hintSerializedLen(),
};
}
};

0 comments on commit 698dffd

Please sign in to comment.