From 3d82a086459eb709f0707efd3d182add2155b2f8 Mon Sep 17 00:00:00 2001 From: rkapka Date: Thu, 28 Oct 2021 11:00:19 +0200 Subject: [PATCH 1/2] Byte32 --- beacon_state_arrays.go | 56 +++++++++++++++++++++++++++++ beacon_state_arrays_test.go | 70 +++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 beacon_state_arrays.go create mode 100644 beacon_state_arrays_test.go diff --git a/beacon_state_arrays.go b/beacon_state_arrays.go new file mode 100644 index 0000000..841fdd0 --- /dev/null +++ b/beacon_state_arrays.go @@ -0,0 +1,56 @@ +package types + +import ( + "fmt" + + fssz "github.com/ferranbt/fastssz" +) + +var _ fssz.HashRoot = (Byte32)([32]byte{}) +var _ fssz.Marshaler = (*Byte32)(nil) +var _ fssz.Unmarshaler = (*Byte32)(nil) + +// Byte32 represents a 32 bytes Byte32 object in Ethereum beacon chain consensus. +type Byte32 [32]byte + +// HashTreeRoot returns calculated hash root. +func (e Byte32) HashTreeRoot() ([32]byte, error) { + return fssz.HashWithDefaultHasher(e) +} + +// HashTreeRootWith hashes a Byte32 object with a Hasher from the default HasherPool. +func (e Byte32) HashTreeRootWith(hh *fssz.Hasher) error { + hh.PutBytes(e[:]) + return nil +} + +// UnmarshalSSZ deserializes the provided bytes buffer into the Byte32 object. +func (e *Byte32) UnmarshalSSZ(buf []byte) error { + if len(buf) != e.SizeSSZ() { + return fmt.Errorf("expected buffer of length %d received %d", e.SizeSSZ(), len(buf)) + } + + var b Byte32 + copy(b[:], buf) + *e = b + return nil +} + +// MarshalSSZTo marshals Byte32 with the provided byte slice. +func (e *Byte32) MarshalSSZTo(dst []byte) ([]byte, error) { + marshalled, err := e.MarshalSSZ() + if err != nil { + return nil, err + } + return append(dst, marshalled...), nil +} + +// MarshalSSZ marshals Byte32 into a serialized object. +func (e *Byte32) MarshalSSZ() ([]byte, error) { + return e[:], nil +} + +// SizeSSZ returns the size of the serialized object. +func (e *Byte32) SizeSSZ() int { + return 32 +} diff --git a/beacon_state_arrays_test.go b/beacon_state_arrays_test.go new file mode 100644 index 0000000..38915b3 --- /dev/null +++ b/beacon_state_arrays_test.go @@ -0,0 +1,70 @@ +package types + +import ( + "reflect" + "testing" +) + +func TestByte32_Casting(t *testing.T) { + var b [32]byte + d := Byte32(b) + if !reflect.DeepEqual([32]byte(d), b) { + t.Errorf("Unequal: %v = %v", d, b) + } +} + +func TestByte32_UnmarshalSSZ(t *testing.T) { + t.Run("Ok", func(t *testing.T) { + d := Byte32{} + var b = [32]byte{'f', 'o', 'o'} + err := d.UnmarshalSSZ(b[:]) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if !reflect.DeepEqual(b, [32]byte(d)) { + t.Errorf("Unequal: %v = %v", b, [32]byte(d)) + } + }) + + t.Run("Wrong slice length", func(t *testing.T) { + d := Byte32{} + var b = [16]byte{'f', 'o', 'o'} + err := d.UnmarshalSSZ(b[:]) + if err == nil { + t.Error("Expected error") + } + }) +} + +func TestByte32_MarshalSSZTo(t *testing.T) { + d := Byte32{'f','o','o'} + dst := []byte("bar") + b, err := d.MarshalSSZTo(dst) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + rest := [29]byte{} + expected := append([]byte("barfoo"), rest[:]...) + if !reflect.DeepEqual(expected, b) { + t.Errorf("Unequal: %v = %v", expected, b) + } +} + +func TestByte32_MarshalSSZ(t *testing.T) { + d := Byte32{'f','o','o'} + b, err := d.MarshalSSZ() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + actual := [32]byte(d) + if !reflect.DeepEqual(b[:], actual[:]) { + t.Errorf("Unequal: %v = %v", b, [32]byte(d)) + } +} + +func TestByte32_SizeSSZ(t *testing.T) { + d := Byte32{} + if d.SizeSSZ() != 32 { + t.Errorf("Wrong SSZ size. Expected %v vs actual %v", 32, d.SizeSSZ()) + } +} From 40fec4b943c923826f08374696f4f4e45a6b08b1 Mon Sep 17 00:00:00 2001 From: rkapka Date: Thu, 28 Oct 2021 14:06:54 +0200 Subject: [PATCH 2/2] StateRoots and RandaoMixes --- beacon_state_arrays.go | 124 ++++++++++++++++++++++++++ beacon_state_arrays_test.go | 173 +++++++++++++++++++++++++++++++++++- 2 files changed, 295 insertions(+), 2 deletions(-) diff --git a/beacon_state_arrays.go b/beacon_state_arrays.go index 841fdd0..0b0eb18 100644 --- a/beacon_state_arrays.go +++ b/beacon_state_arrays.go @@ -6,6 +6,8 @@ import ( fssz "github.com/ferranbt/fastssz" ) +const stateRootsSize = 8192 + var _ fssz.HashRoot = (Byte32)([32]byte{}) var _ fssz.Marshaler = (*Byte32)(nil) var _ fssz.Unmarshaler = (*Byte32)(nil) @@ -54,3 +56,125 @@ func (e *Byte32) MarshalSSZ() ([]byte, error) { func (e *Byte32) SizeSSZ() int { return 32 } + +var _ fssz.HashRoot = (StateRoots)([stateRootsSize][32]byte{}) +var _ fssz.Marshaler = (*StateRoots)(nil) +var _ fssz.Unmarshaler = (*StateRoots)(nil) + +// Byte32 represents a 32 bytes StateRoots object in Ethereum beacon chain consensus. +type StateRoots [stateRootsSize][32]byte + +// HashTreeRoot returns calculated hash root. +func (r StateRoots) HashTreeRoot() ([32]byte, error) { + return fssz.HashWithDefaultHasher(r) +} + +// HashTreeRootWith hashes a StateRoots object with a Hasher from the default HasherPool. +func (r StateRoots) HashTreeRootWith(hh *fssz.Hasher) error { + index := hh.Index() + for _, sRoot := range r { + hh.Append(sRoot[:]) + } + hh.Merkleize(index) + return nil +} + +// UnmarshalSSZ deserializes the provided bytes buffer into the StateRoots object. +func (r *StateRoots) UnmarshalSSZ(buf []byte) error { + if len(buf) != r.SizeSSZ() { + return fmt.Errorf("expected buffer of length %d received %d", r.SizeSSZ(), len(buf)) + } + + var roots StateRoots + for i, _ := range roots { + copy(roots[i][:], buf[i*32:(i+1)*32]) + } + *r = roots + return nil +} + +// MarshalSSZTo marshals StateRoots with the provided byte slice. +func (r *StateRoots) MarshalSSZTo(dst []byte) ([]byte, error) { + marshalled, err := r.MarshalSSZ() + if err != nil { + return nil, err + } + return append(dst, marshalled...), nil +} + +// MarshalSSZ marshals StateRoots into a serialized object. +func (r *StateRoots) MarshalSSZ() ([]byte, error) { + marshalled := make([]byte, stateRootsSize*32) + for i, r32 := range r { + for j, rr := range r32 { + marshalled[i*32+j] = rr + } + } + return marshalled, nil +} + +// SizeSSZ returns the size of the serialized object. +func (r *StateRoots) SizeSSZ() int { + return stateRootsSize * 32 +} + +var _ fssz.HashRoot = (RandaoMixes)([][32]byte{}) +var _ fssz.Marshaler = (*RandaoMixes)(nil) +var _ fssz.Unmarshaler = (*RandaoMixes)(nil) + +// Byte32 represents a 32 bytes RandaoMixes object in Ethereum beacon chain consensus. +type RandaoMixes [][32]byte + +// HashTreeRoot returns calculated hash root. +func (r RandaoMixes) HashTreeRoot() ([32]byte, error) { + return fssz.HashWithDefaultHasher(r) +} + +// HashTreeRootWith hashes a RandaoMixes object with a Hasher from the default HasherPool. +func (r RandaoMixes) HashTreeRootWith(hh *fssz.Hasher) error { + index := hh.Index() + for _, sRoot := range r { + hh.Append(sRoot[:]) + } + hh.Merkleize(index) + return nil +} + +// UnmarshalSSZ deserializes the provided bytes buffer into the RandaoMixes object. +func (r *RandaoMixes) UnmarshalSSZ(buf []byte) error { + if len(buf) != r.SizeSSZ() { + return fmt.Errorf("expected buffer of length %d received %d", r.SizeSSZ(), len(buf)) + } + + mixes := make([][32]byte, len(buf)/32) + for i, _ := range mixes { + copy(mixes[i][:], buf[i*32:(i+1)*32]) + } + *r = mixes + return nil +} + +// MarshalSSZTo marshals RandaoMixes with the provided byte slice. +func (r *RandaoMixes) MarshalSSZTo(dst []byte) ([]byte, error) { + marshalled, err := r.MarshalSSZ() + if err != nil { + return nil, err + } + return append(dst, marshalled...), nil +} + +// MarshalSSZ marshals RandaoMixes into a serialized object. +func (r *RandaoMixes) MarshalSSZ() ([]byte, error) { + marshalled := make([]byte, len(*r)*32) + for i, r32 := range *r { + for j, rr := range r32 { + marshalled[i*32+j] = rr + } + } + return marshalled, nil +} + +// SizeSSZ returns the size of the serialized object. +func (r *RandaoMixes) SizeSSZ() int { + return len(*r) * 32 +} diff --git a/beacon_state_arrays_test.go b/beacon_state_arrays_test.go index 38915b3..d2228c5 100644 --- a/beacon_state_arrays_test.go +++ b/beacon_state_arrays_test.go @@ -37,7 +37,7 @@ func TestByte32_UnmarshalSSZ(t *testing.T) { } func TestByte32_MarshalSSZTo(t *testing.T) { - d := Byte32{'f','o','o'} + d := Byte32{'f', 'o', 'o'} dst := []byte("bar") b, err := d.MarshalSSZTo(dst) if err != nil { @@ -51,7 +51,7 @@ func TestByte32_MarshalSSZTo(t *testing.T) { } func TestByte32_MarshalSSZ(t *testing.T) { - d := Byte32{'f','o','o'} + d := Byte32{'f', 'o', 'o'} b, err := d.MarshalSSZ() if err != nil { t.Fatalf("Unexpected error: %v", err) @@ -68,3 +68,172 @@ func TestByte32_SizeSSZ(t *testing.T) { t.Errorf("Wrong SSZ size. Expected %v vs actual %v", 32, d.SizeSSZ()) } } + +func TestStateRoots_Casting(t *testing.T) { + var b [stateRootsSize][32]byte + d := StateRoots(b) + if !reflect.DeepEqual([stateRootsSize][32]byte(d), b) { + t.Errorf("Unequal: %v = %v", d, b) + } +} + +func TestStateRoots_UnmarshalSSZ(t *testing.T) { + t.Run("Ok", func(t *testing.T) { + d := StateRoots{} + var b [stateRootsSize][32]byte + b[0] = [32]byte{'f', 'o', 'o'} + b[1] = [32]byte{'b', 'a', 'r'} + bb := make([]byte, stateRootsSize*32) + for i, elem32 := range b { + for j, elem := range elem32 { + bb[i*32+j] = elem + } + } + err := d.UnmarshalSSZ(bb) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if !reflect.DeepEqual(b, [stateRootsSize][32]byte(d)) { + t.Errorf("Unequal: %v = %v", b, [stateRootsSize][32]byte(d)) + } + }) + + t.Run("Wrong slice length", func(t *testing.T) { + d := StateRoots{} + var b [stateRootsSize][16]byte + b[0] = [16]byte{'f', 'o', 'o'} + b[1] = [16]byte{'b', 'a', 'r'} + bb := make([]byte, stateRootsSize*16) + for i, elem16 := range b { + for j, elem := range elem16 { + bb[i*16+j] = elem + } + } + err := d.UnmarshalSSZ(bb) + if err == nil { + t.Error("Expected error") + } + }) +} + +func TestStateRoots_MarshalSSZTo(t *testing.T) { + var d StateRoots + dst := []byte("foo") + b, err := d.MarshalSSZTo(dst) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + expected := []byte{'f', 'o', 'o'} + actual := []byte{b[0], b[1], b[2]} + if !reflect.DeepEqual(expected, actual) { + t.Errorf("Unequal: %v = %v", expected, actual) + } +} + +func TestStateRoots_MarshalSSZ(t *testing.T) { + d := StateRoots{} + d[0] = [32]byte{'f', 'o', 'o'} + d[1] = [32]byte{'b', 'a', 'r'} + b, err := d.MarshalSSZ() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if !reflect.DeepEqual(d[0][:], b[0:32]) { + t.Errorf("Unequal: %v = %v", d[0], b[0:32]) + } + if !reflect.DeepEqual(d[1][:], b[32:64]) { + t.Errorf("Unequal: %v = %v", d[0], b[32:64]) + } +} + +func TestStateRoots_SizeSSZ(t *testing.T) { + d := StateRoots{} + if d.SizeSSZ() != stateRootsSize*32 { + t.Errorf("Wrong SSZ size. Expected %v vs actual %v", stateRootsSize*32, d.SizeSSZ()) + } +} + +func TestRandaoMixes_Casting(t *testing.T) { + b := make([][32]byte, 4) + d := RandaoMixes(b) + if !reflect.DeepEqual([][32]byte(d), b) { + t.Errorf("Unequal: %v = %v", d, b) + } +} + +func TestRandaoMixes_UnmarshalSSZ(t *testing.T) { + t.Run("Ok", func(t *testing.T) { + d := RandaoMixes(make([][32]byte, 2)) + b := make([][32]byte, 2) + b[0] = [32]byte{'f', 'o', 'o'} + b[1] = [32]byte{'b', 'a', 'r'} + bb := make([]byte, 2*32) + for i, elem32 := range b { + for j, elem := range elem32 { + bb[i*32+j] = elem + } + } + err := d.UnmarshalSSZ(bb) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if !reflect.DeepEqual(b, [][32]byte(d)) { + t.Errorf("Unequal: %v = %v", b, [][32]byte(d)) + } + }) + + t.Run("Wrong slice length", func(t *testing.T) { + d := RandaoMixes(make([][32]byte, 2)) + b := make([][16]byte, 2) + b[0] = [16]byte{'f', 'o', 'o'} + b[1] = [16]byte{'b', 'a', 'r'} + bb := make([]byte, 2*16) + for i, elem16 := range b { + for j, elem := range elem16 { + bb[i*16+j] = elem + } + } + err := d.UnmarshalSSZ(bb) + if err == nil { + t.Error("Expected error") + } + }) +} + +func TestRandaoMixes_MarshalSSZTo(t *testing.T) { + d := RandaoMixes(make([][32]byte, 1)) + d[0] = [32]byte{'f', 'o', 'o'} + dst := []byte("bar") + b, err := d.MarshalSSZTo(dst) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + expected := []byte{'b', 'a', 'r', 'f', 'o', 'o'} + actual := []byte{b[0], b[1], b[2], b[3], b[4], b[5]} + if !reflect.DeepEqual(expected, actual) { + t.Errorf("Unequal: %v = %v", expected, actual) + } +} + +func TestRandaoMixes_MarshalSSZ(t *testing.T) { + d := RandaoMixes(make([][32]byte, 2)) + d[0] = [32]byte{'f', 'o', 'o'} + d[1] = [32]byte{'b', 'a', 'r'} + b, err := d.MarshalSSZ() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if !reflect.DeepEqual(d[0][:], b[0:32]) { + t.Errorf("Unequal: %v = %v", d[0], b[0:32]) + } + if !reflect.DeepEqual(d[1][:], b[32:64]) { + t.Errorf("Unequal: %v = %v", d[0], b[32:64]) + } +} + +func TestRandaoMixes_SizeSSZ(t *testing.T) { + d := RandaoMixes(make([][32]byte, 2)) + if d.SizeSSZ() != 2*32 { + t.Errorf("Wrong SSZ size. Expected %v vs actual %v", 2*32, d.SizeSSZ()) + } +}