Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pkgs/database/src/test_helpers.zig
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ pub fn createDummyBlock(allocator: Allocator, slot: u64, proposer_index: u64, pa
pub fn createDummyState(allocator: Allocator, slot: u64, num_validators: u64, genesis_time: u64, justified_slot: u64, finalized_slot: u64, justified_root_fill: u8, finalized_root_fill: u8) !types.BeamState {
var validators = try types.Validators.init(allocator);
errdefer validators.deinit();
for (0..num_validators) |_| {
try validators.append(.{ .pubkey = [_]u8{0} ** 52 });
for (0..num_validators) |index| {
try validators.append(.{ .pubkey = [_]u8{0} ** 52, .index = @as(types.ValidatorIndex, @intCast(index)) });
}

var test_state = types.BeamState{
Expand Down
131 changes: 126 additions & 5 deletions pkgs/types/src/state.zig
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,7 @@ pub const BeamState = struct {

// Populate validators from genesis pubkeys
for (genesis.validator_pubkeys) |pubkey| {
const val = validator.Validator{
.pubkey = pubkey,
};
const val = validator.Validator{ .pubkey = pubkey };
try validators.append(val);
}

Expand All @@ -112,8 +110,8 @@ pub const BeamState = struct {
.slot = 0,
.latest_block_header = genesis_block_header,
// mini3sf
.latest_justified = .{ .root = [_]u8{0} ** 32, .slot = 0 },
.latest_finalized = .{ .root = [_]u8{0} ** 32, .slot = 0 },
.latest_justified = .{ .root = utils.ZERO_HASH, .slot = 0 },
.latest_finalized = .{ .root = utils.ZERO_HASH, .slot = 0 },
.historical_block_hashes = historical_block_hashes,
.justified_slots = justified_slots,
.validators = validators,
Expand Down Expand Up @@ -699,3 +697,126 @@ test "encode decode state roundtrip" {
try std.testing.expect(decoded.justifications_validators.len() == state.justifications_validators.len());
try std.testing.expect(decoded.validators.len() == state.validators.len());
}

test "genesis block hash comparison" {
var arena_allocator = std.heap.ArenaAllocator.init(std.testing.allocator);
defer arena_allocator.deinit();
const allocator = arena_allocator.allocator();

// Create first genesis state with 3 validators
var pubkeys1 = try allocator.alloc(utils.Bytes52, 3);
defer allocator.free(pubkeys1);
{
var i: usize = 0;
while (i < pubkeys1.len) : (i += 1) {
@memset(&pubkeys1[i], @intCast(i + 1)); // Fill with different values (1, 2, 3)
}
}

const genesis_spec1 = utils.GenesisSpec{
.genesis_time = 1000,
.validator_pubkeys = pubkeys1,
};

var genesis_state1: BeamState = undefined;
try genesis_state1.genGenesisState(allocator, genesis_spec1);
defer genesis_state1.deinit();

// Generate genesis block from first state
var genesis_block1: block.BeamBlock = undefined;
try genesis_state1.genGenesisBlock(allocator, &genesis_block1);
defer genesis_block1.deinit();

// Compute hash of first genesis block
var genesis_block_hash1: Root = undefined;
try ssz.hashTreeRoot(block.BeamBlock, genesis_block1, &genesis_block_hash1, allocator);
std.debug.print("genesis_block_hash1 =0x{s}\n", .{std.fmt.fmtSliceHexLower(&genesis_block_hash1)});

// Create a second genesis state with same config but regenerated (should produce same hash)
var genesis_state1_copy: BeamState = undefined;
try genesis_state1_copy.genGenesisState(allocator, genesis_spec1);
defer genesis_state1_copy.deinit();

var genesis_block1_copy: block.BeamBlock = undefined;
try genesis_state1_copy.genGenesisBlock(allocator, &genesis_block1_copy);
defer genesis_block1_copy.deinit();

var genesis_block_hash1_copy: Root = undefined;
try ssz.hashTreeRoot(block.BeamBlock, genesis_block1_copy, &genesis_block_hash1_copy, allocator);

// Same genesis spec should produce same hash
try std.testing.expect(std.mem.eql(u8, &genesis_block_hash1, &genesis_block_hash1_copy));

// Create second genesis state with different validators
var pubkeys2 = try allocator.alloc(utils.Bytes52, 3);
defer allocator.free(pubkeys2);
{
var i: usize = 0;
while (i < pubkeys2.len) : (i += 1) {
@memset(&pubkeys2[i], @intCast(i + 10)); // Fill with different values (10, 11, 12)
}
}

const genesis_spec2 = utils.GenesisSpec{
.genesis_time = 1000, // Same genesis_time but different validators
.validator_pubkeys = pubkeys2,
};

var genesis_state2: BeamState = undefined;
try genesis_state2.genGenesisState(allocator, genesis_spec2);
defer genesis_state2.deinit();

var genesis_block2: block.BeamBlock = undefined;
try genesis_state2.genGenesisBlock(allocator, &genesis_block2);
defer genesis_block2.deinit();

var genesis_block_hash2: Root = undefined;
try ssz.hashTreeRoot(block.BeamBlock, genesis_block2, &genesis_block_hash2, allocator);
std.debug.print("genesis_block_hash2 =0x{s}\n", .{std.fmt.fmtSliceHexLower(&genesis_block_hash2)});

// Different validators should produce different genesis block hash
try std.testing.expect(!std.mem.eql(u8, &genesis_block_hash1, &genesis_block_hash2));

// Create third genesis state with same validators but different genesis_time
var pubkeys3 = try allocator.alloc(utils.Bytes52, 3);
defer allocator.free(pubkeys3);
{
var i: usize = 0;
while (i < pubkeys3.len) : (i += 1) {
@memset(&pubkeys3[i], @intCast(i + 1)); // Same as pubkeys1
}
}

const genesis_spec3 = utils.GenesisSpec{
.genesis_time = 2000, // Different genesis_time but same validators
.validator_pubkeys = pubkeys3,
};

var genesis_state3: BeamState = undefined;
try genesis_state3.genGenesisState(allocator, genesis_spec3);
defer genesis_state3.deinit();

var genesis_block3: block.BeamBlock = undefined;
try genesis_state3.genGenesisBlock(allocator, &genesis_block3);
defer genesis_block3.deinit();

var genesis_block_hash3: Root = undefined;
try ssz.hashTreeRoot(block.BeamBlock, genesis_block3, &genesis_block_hash3, allocator);
std.debug.print("genesis_block_hash3 =0x{s}\n", .{std.fmt.fmtSliceHexLower(&genesis_block_hash3)});

// Different genesis_time should produce different genesis block hash
try std.testing.expect(!std.mem.eql(u8, &genesis_block_hash1, &genesis_block_hash3));

// // Compare genesis block hashes with expected hex values
const hash1_hex = try std.fmt.allocPrint(allocator, "0x{s}", .{std.fmt.fmtSliceHexLower(&genesis_block_hash1)});
defer allocator.free(hash1_hex);
try std.testing.expectEqualStrings(hash1_hex, "0x4c0bcc4750b71818224a826cd59f8bcb75ae2920eb3e75b4097b818be6d1049a");

const hash2_hex = try std.fmt.allocPrint(allocator, "0x{s}", .{std.fmt.fmtSliceHexLower(&genesis_block_hash2)});
defer allocator.free(hash2_hex);
try std.testing.expectEqualStrings(hash2_hex, "0x639b6162e6b432653a77a64b678717e7634428eda88ad6ccb1862e6397c0c47b");

const hash3_hex = try std.fmt.allocPrint(allocator, "0x{s}", .{std.fmt.fmtSliceHexLower(&genesis_block_hash3)});
defer allocator.free(hash3_hex);
try std.testing.expectEqualStrings(hash3_hex, "0x6593976e31c915b5d534e2ee6172652aed7690be24777947de39c726aa2af59e");
}
24 changes: 21 additions & 3 deletions pkgs/types/src/validator.zig
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
const std = @import("std");
const ssz = @import("ssz");

const params = @import("@zeam/params");

const attestation = @import("./attestation.zig");
const utils = @import("./utils.zig");

const Attestation = attestation.Attestation;
const AttestationData = attestation.AttestationData;
const Allocator = std.mem.Allocator;
const Bytes52 = utils.Bytes52;
const ValidatorIndex = utils.ValidatorIndex;

const bytesToHex = utils.BytesToHex;
const json = std.json;
Expand All @@ -14,25 +20,37 @@ pub const Validators = ssz.utils.List(Validator, params.VALIDATOR_REGISTRY_LIMIT

pub const Validator = struct {
pubkey: Bytes52,
index: ValidatorIndex = 0,

const Self = @This();

pub fn toJson(self: *const Validator, allocator: Allocator) !json.Value {
pub fn toJson(self: *const Self, allocator: Allocator) !json.Value {
var obj = json.ObjectMap.init(allocator);
try obj.put("pubkey", json.Value{ .string = try bytesToHex(allocator, &self.pubkey) });
try obj.put("index", json.Value{ .integer = @as(i64, @intCast(self.index)) });
return json.Value{ .object = obj };
}

pub fn getPubkey(self: *const Validator) []const u8 {
pub fn getPubkey(self: *const Self) []const u8 {
return &self.pubkey;
}

pub fn toJsonString(self: *const Validator, allocator: Allocator) ![]const u8 {
pub fn produceAttestation(self: *const Self, data: AttestationData) Attestation {
return Attestation{
.data = data,
.validator_id = self.index,
};
}

pub fn toJsonString(self: *const Self, allocator: Allocator) ![]const u8 {
var json_value = try self.toJson(allocator);
defer freeJson(&json_value, allocator);
return utils.jsonToString(allocator, json_value);
}

pub fn freeJson(val: *json.Value, allocator: Allocator) void {
allocator.free(val.object.get("pubkey").?.string);
allocator.free(val.object.get("index").?.string);
val.object.deinit();
}
};
Loading