From 233690620ecaf4402d5c3172f579b0eb3d7fbb03 Mon Sep 17 00:00:00 2001 From: a Date: Sun, 7 May 2023 01:24:09 -0500 Subject: [PATCH 01/34] new branch --- cl/cltypes/solid/hashutil.go | 76 +++++++++ cl/cltypes/solid/interfaces.go | 14 ++ cl/cltypes/solid/uint64slice_byte.go | 152 ++++++++++++++++++ cl/cltypes/solid/uint64slice_byte_test.go | 34 ++++ cl/cltypes/solid/uint64slice_simple.go | 68 ++++++++ cl/cltypes/solid/validator.go | 124 ++++++++++++++ cl/cltypes/validator.go | 80 +++------ cl/merkle_tree/hasher.go | 29 +++- cl/merkle_tree/merkle_root.go | 8 + cl/merkle_tree/primitives.go | 9 ++ cmd/erigon-cl/core/state/accessors.go | 23 +-- cmd/erigon-cl/core/state/accessors_test.go | 37 +++-- cmd/erigon-cl/core/state/cache.go | 4 +- cmd/erigon-cl/core/state/cache_accessors.go | 13 +- cmd/erigon-cl/core/state/cache_mutators.go | 6 +- cmd/erigon-cl/core/state/cache_setters.go | 2 +- cmd/erigon-cl/core/state/copy.go | 16 +- cmd/erigon-cl/core/state/mutators_test.go | 59 +++---- cmd/erigon-cl/core/state/raw/copy.go | 22 +-- cmd/erigon-cl/core/state/raw/getters.go | 31 ++-- cmd/erigon-cl/core/state/raw/hashing.go | 12 +- cmd/erigon-cl/core/state/raw/setters.go | 58 ++++--- cmd/erigon-cl/core/state/raw/ssz.go | 34 ++-- cmd/erigon-cl/core/state/raw/state.go | 9 +- cmd/erigon-cl/core/state/raw/test_util.go | 6 +- .../core/state/shuffling/shuffling.go | 2 +- cmd/erigon-cl/core/state/util.go | 27 ++-- .../finalization_and_justification.go | 26 +-- cmd/erigon-cl/core/transition/operations.go | 14 +- .../core/transition/process_attestations.go | 8 +- .../process_bls_to_execution_change.go | 7 +- .../process_effective_balance_update.go | 17 +- .../core/transition/process_epoch.go | 6 +- .../transition/process_registry_updates.go | 21 ++- .../process_rewards_and_penalties.go | 73 +++++---- .../core/transition/process_slashings.go | 18 ++- .../core/transition/process_slots.go | 3 +- cmd/erigon-cl/core/transition/processing.go | 9 +- cmd/erigon-cl/forkchoice/checkpoint_state.go | 10 +- cmd/erigon-cl/forkchoice/utils.go | 8 +- 40 files changed, 859 insertions(+), 316 deletions(-) create mode 100644 cl/cltypes/solid/hashutil.go create mode 100644 cl/cltypes/solid/interfaces.go create mode 100644 cl/cltypes/solid/uint64slice_byte.go create mode 100644 cl/cltypes/solid/uint64slice_byte_test.go create mode 100644 cl/cltypes/solid/uint64slice_simple.go create mode 100644 cl/cltypes/solid/validator.go diff --git a/cl/cltypes/solid/hashutil.go b/cl/cltypes/solid/hashutil.go new file mode 100644 index 00000000000..39a66233c31 --- /dev/null +++ b/cl/cltypes/solid/hashutil.go @@ -0,0 +1,76 @@ +package solid + +import ( + "fmt" + + "github.com/ledgerwatch/erigon/cl/merkle_tree" + "github.com/ledgerwatch/erigon/cl/utils" + "github.com/prysmaticlabs/gohashtree" +) + +func TreeHashFlatSlice(input []byte, res []byte) (err error) { + err = merkle_tree.MerkleRootFromFlatLeaves(input, res) + if err != nil { + return err + } + return nil +} + +// MerkleizeVector uses our optimized routine to hash a list of 32-byte +// elements. +func MerkleizeVector(elements [][32]byte, length uint64) ([32]byte, error) { + depth := getDepth(length) + // Return zerohash at depth + if len(elements) == 0 { + return merkle_tree.ZeroHashes[depth], nil + } + for i := uint8(0); i < depth; i++ { + // Sequential + layerLen := len(elements) + if layerLen%2 == 1 { + elements = append(elements, merkle_tree.ZeroHashes[i]) + } + outputLen := len(elements) / 2 + if err := gohashtree.Hash(elements, elements); err != nil { + return [32]byte{}, err + } + elements = elements[:outputLen] + } + return elements[0], nil +} + +// MerkleizeVector uses our optimized routine to hash a list of 32-byte +// elements. +func MerkleizeFlatLeaves(elements []byte) ([]byte, error) { + // merkleizeTrieLeaves returns intermediate roots of given leaves. + layer := make([]byte, len(elements)/2) + for len(elements) > 32 { + if !utils.IsPowerOf2(uint64(len(elements))) { + return nil, fmt.Errorf("hash layer is a non power of 2: %d", len(elements)) + } + if err := gohashtree.HashByteSlice(layer, elements); err != nil { + return nil, err + } + elements = layer[:len(elements)/2] + } + return elements[:32], nil +} + +func getDepth(v uint64) uint8 { + // If there are 0 or 1 nodes, the depth is 0. + if v <= 1 { + return 0 + } + + // Initialize the depth to 0. + depth := uint8(0) + + // Divide the number of nodes by 2 until it is less than or equal to 1. + // The number of iterations is the depth of the tree. + for v > 1 { + v >>= 1 + depth++ + } + + return depth +} diff --git a/cl/cltypes/solid/interfaces.go b/cl/cltypes/solid/interfaces.go new file mode 100644 index 00000000000..b9cc9fddbd4 --- /dev/null +++ b/cl/cltypes/solid/interfaces.go @@ -0,0 +1,14 @@ +package solid + +type Uint64Slice interface { + Clear() + CopyTo(Uint64Slice) + Range(fn func(index int, value uint64, length int) bool) + Pop() uint64 + Append(v uint64) + Get(index int) uint64 + Set(index int, v uint64) + Length() int + Cap() int + HashSSZTo(xs []byte) error +} diff --git a/cl/cltypes/solid/uint64slice_byte.go b/cl/cltypes/solid/uint64slice_byte.go new file mode 100644 index 00000000000..a1dbae3a945 --- /dev/null +++ b/cl/cltypes/solid/uint64slice_byte.go @@ -0,0 +1,152 @@ +package solid + +import ( + "encoding/binary" + + "github.com/ledgerwatch/erigon/cl/merkle_tree" + "github.com/ledgerwatch/erigon/cl/utils" + "github.com/prysmaticlabs/gohashtree" +) + +type byteBasedUint64Slice struct { + u []byte + hashBuf []byte + + l int // len + c int // cap +} + +func NewUint64Slice(limit int) Uint64Slice { + o := &byteBasedUint64Slice{ + c: limit, + } + o.u = make([]byte, 0) + return o +} + +func (arr *byteBasedUint64Slice) Clear() { + arr.l = 0 + for i := range arr.u { + arr.u[i] = 0 + } +} + +func (arr *byteBasedUint64Slice) CopyTo(target Uint64Slice) { + target.Clear() + switch c := target.(type) { + case *byteBasedUint64Slice: + c.c = arr.c + c.l = arr.l + if len(c.u) < len(arr.u) { + c.u = make([]byte, len(arr.u)) + } + c.u = c.u[:len(arr.u)] + copy(c.u, arr.u) + return + default: + } + target.Range(func(index int, value uint64, length int) bool { + target.Append(value) + return true + }) +} + +func (arr *byteBasedUint64Slice) depth() int { + return int(getDepth(uint64(arr.c) / 4)) +} + +func (arr *byteBasedUint64Slice) Range(fn func(index int, value uint64, length int) bool) { + for i := 0; i < arr.l; i++ { + cont := fn(i, arr.Get(i), arr.l) + if !cont { + break + } + } +} + +func (arr *byteBasedUint64Slice) Pop() uint64 { + offset := (arr.l - 1) * 8 + val := binary.LittleEndian.Uint64(arr.u[offset : offset+8]) + binary.LittleEndian.PutUint64(arr.u[offset:offset+8], 0) + arr.l = arr.l - 1 + return val +} + +func (arr *byteBasedUint64Slice) makeBuf(size int) { + diff := size - len(arr.hashBuf) + if diff > 0 { + arr.hashBuf = append(arr.hashBuf, make([]byte, diff)...) + } + arr.hashBuf = arr.hashBuf[:size] +} + +func (arr *byteBasedUint64Slice) Append(v uint64) { + if len(arr.u) <= arr.l*8 { + arr.u = append(arr.u, make([]byte, 32)...) + } + offset := arr.l * 8 + binary.LittleEndian.PutUint64(arr.u[offset:offset+8], v) + arr.l = arr.l + 1 +} + +func (arr *byteBasedUint64Slice) Get(index int) uint64 { + if index >= arr.l { + panic("index out of range") + } + offset := index * 8 + return binary.LittleEndian.Uint64(arr.u[offset : offset+8]) +} + +func (arr *byteBasedUint64Slice) Set(index int, v uint64) { + if index >= arr.l { + panic("index out of range") + } + offset := index * 8 + binary.LittleEndian.PutUint64(arr.u[offset:offset+8], v) +} + +func (arr *byteBasedUint64Slice) Length() int { + return arr.l +} + +func (arr *byteBasedUint64Slice) Cap() int { + return arr.c +} + +func (arr *byteBasedUint64Slice) HashSSZTo(xs []byte) error { + depth := getDepth((uint64(arr.c)*8 + 31) / 32) + baseRoot := [32]byte{} + if arr.l == 0 { + copy(baseRoot[:], merkle_tree.ZeroHashes[depth][:]) + } else { + err := arr.getBaseHash(baseRoot[:]) + if err != nil { + return err + } + } + lengthRoot := merkle_tree.Uint64Root(uint64(arr.l)) + ans := utils.Keccak256(baseRoot[:], lengthRoot[:]) + copy(xs, ans[:]) + return nil +} + +func (arr *byteBasedUint64Slice) getBaseHash(xs []byte) error { + depth := getDepth((uint64(arr.c)*8 + 31) / 32) + offset := 32*((arr.l-1)/4) + 32 + elements := arr.u[:offset] + for i := uint8(0); i < depth; i++ { + // Sequential + layerLen := len(elements) + if layerLen%64 == 32 { + elements = append(elements, merkle_tree.ZeroHashes[i][:]...) + } + outputLen := len(elements) / 2 + arr.makeBuf(outputLen) + if err := gohashtree.HashByteSlice(arr.hashBuf, elements); err != nil { + return err + } + elements = arr.hashBuf + } + copy(xs, elements[:32]) + return nil +} diff --git a/cl/cltypes/solid/uint64slice_byte_test.go b/cl/cltypes/solid/uint64slice_byte_test.go new file mode 100644 index 00000000000..1fd7545225f --- /dev/null +++ b/cl/cltypes/solid/uint64slice_byte_test.go @@ -0,0 +1,34 @@ +package solid_test + +import ( + "log" + "testing" + + "github.com/ledgerwatch/erigon/cl/cltypes/solid" + "github.com/ledgerwatch/erigon/cl/merkle_tree" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestUint64SliceBasic(t *testing.T) { + slice := solid.NewUint64Slice(8) + + slice.Append(3) + slice.Append(2) + slice.Append(1) + + assert.EqualValues(t, 3, slice.Get(0)) + assert.EqualValues(t, 2, slice.Get(1)) + assert.EqualValues(t, 1, slice.Get(2)) + + out := [32]byte{} + err := slice.HashSSZTo(out[:]) + require.NoError(t, err) + + nums := []uint64{3, 2, 1} + root, err := merkle_tree.Uint64ListRootWithLimit(nums, 2) + require.NoError(t, err) + log.Printf("merkl tree: %x", root) + log.Printf("ours tree: %x", out) + +} diff --git a/cl/cltypes/solid/uint64slice_simple.go b/cl/cltypes/solid/uint64slice_simple.go new file mode 100644 index 00000000000..b74aab2e07d --- /dev/null +++ b/cl/cltypes/solid/uint64slice_simple.go @@ -0,0 +1,68 @@ +package solid + +import ( + "github.com/ledgerwatch/erigon/cl/merkle_tree" +) + +type uint64SliceSimple struct { + u []uint64 + c int +} + +func NewSimpleUint64Slice(cap int) Uint64Slice { + return &uint64SliceSimple{ + c: cap, + } +} + +func (u *uint64SliceSimple) Clear() { + u.u = u.u[:0] +} + +func (u *uint64SliceSimple) CopyTo(target Uint64Slice) { + target.Clear() + for _, v := range u.u { + target.Append(v) + } +} + +func (u *uint64SliceSimple) Range(fn func(index int, value uint64, length int) bool) { + //TODO implement me + for i, v := range u.u { + fn(i, v, len(u.u)) + } +} + +func (u *uint64SliceSimple) Pop() (x uint64) { + x, u.u = u.u[0], u.u[1:] + return x +} + +func (u *uint64SliceSimple) Append(v uint64) { + u.u = append(u.u, v) +} + +func (u *uint64SliceSimple) Get(index int) uint64 { + return u.u[index] +} + +func (u *uint64SliceSimple) Set(index int, v uint64) { + u.u[index] = v +} + +func (u *uint64SliceSimple) Length() int { + return len(u.u) +} + +func (u *uint64SliceSimple) Cap() int { + return u.c +} + +func (u *uint64SliceSimple) HashSSZTo(xs []byte) error { + root, err := merkle_tree.Uint64ListRootWithLimit(u.u, (uint64(u.c)*8+31)/32) + if err != nil { + return err + } + copy(xs, root[:]) + return nil +} diff --git a/cl/cltypes/solid/validator.go b/cl/cltypes/solid/validator.go new file mode 100644 index 00000000000..29f5fd28540 --- /dev/null +++ b/cl/cltypes/solid/validator.go @@ -0,0 +1,124 @@ +package solid + +import ( + "encoding/binary" + + "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon/cl/cltypes/ssz" + "github.com/ledgerwatch/erigon/cl/merkle_tree" +) + +// PublicKey 48 +// WithdrawalCredentials 32 +// EffectiveBalance 8 +// Slashed 1 +// ActivationEligibilityEpoch 8 +// ActivationEpoch 8 +// ExitEpoch 8 +// WithdrawableEpoch 8 +// +// total: 121 +const validatorSize = 48 + 32 + 8 + 1 + 8 + 8 + 8 + 8 + +type Validator [validatorSize]byte + +func (v *Validator) CopyTo(dst *Validator) { + copy(dst[:], v[:]) +} + +func (v *Validator) EncodeSSZ(dst []byte) []byte { + buf := dst + buf = append(buf, v[:]...) + return buf +} + +func (v *Validator) DecodeSSZ(buf []byte, _ int) error { + if len(buf) < v.EncodingSizeSSZ() { + return ssz.ErrLowBufferSize + } + copy(v[:], buf) + return nil +} + +func (v *Validator) EncodingSizeSSZ() int { + return 121 +} + +func (v *Validator) PublicKey() (o [48]byte) { + copy(o[:], v[:48]) + return +} +func (v *Validator) WithdrawalCredentials() (o common.Hash) { + copy(o[:], v[48:80]) + return +} +func (v *Validator) EffectiveBalance() uint64 { + return binary.LittleEndian.Uint64(v[80:88]) +} +func (v *Validator) Slashed() bool { + return v[88] != 0 +} +func (v *Validator) ActivationEligibilityEpoch() uint64 { + return binary.LittleEndian.Uint64(v[89:97]) +} +func (v *Validator) ActivationEpoch() uint64 { + return binary.LittleEndian.Uint64(v[97:105]) +} +func (v *Validator) ExitEpoch() uint64 { + return binary.LittleEndian.Uint64(v[105:113]) +} +func (v *Validator) WithdrawableEpoch() uint64 { + return binary.LittleEndian.Uint64(v[113:121]) +} + +func (v *Validator) CopyHashBufferTo(o []byte) error { + for i := 0; i < 64; i++ { + o[i] = 0 + } + copy(o[:64], v[:48]) + err := merkle_tree.InPlacePublicKeyRoot(o[:64]) + if err != nil { + return err + } + copy(o[32:64], v[48:80]) + copy(o[64:96], v[80:88]) + o[96] = v[88] + copy(o[128:160], v[89:97]) + copy(o[160:192], v[97:105]) + copy(o[192:224], v[105:113]) + copy(o[224:256], v[113:121]) + + return nil + +} + +func (v *Validator) SetPublicKey(o [48]byte) { + copy(v[:48], o[:]) + return +} +func (v *Validator) SetWithdrawalCredentials(o common.Hash) { + copy(v[48:80], o[:]) + return +} +func (v *Validator) SetEffectiveBalance(i uint64) { + binary.LittleEndian.PutUint64(v[80:88], i) +} +func (v *Validator) SetSlashed(b bool) { + if b { + v[88] = 1 + return + } + v[88] = 0 +} +func (v *Validator) SetActivationEligibilityEpoch(i uint64) { + binary.LittleEndian.PutUint64(v[89:97], i) +} +func (v *Validator) SetActivationEpoch(i uint64) { + binary.LittleEndian.PutUint64(v[97:105], i) +} +func (v *Validator) SetExitEpoch(i uint64) { + binary.LittleEndian.PutUint64(v[105:113], i) +} +func (v *Validator) SetWithdrawableEpoch(i uint64) { + binary.LittleEndian.PutUint64(v[113:121], i) +} diff --git a/cl/cltypes/validator.go b/cl/cltypes/validator.go index debeef7ff1b..0f8257814d0 100644 --- a/cl/cltypes/validator.go +++ b/cl/cltypes/validator.go @@ -7,6 +7,7 @@ import ( libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon/cl/cltypes/solid" "github.com/ledgerwatch/erigon/cl/cltypes/ssz" "github.com/ledgerwatch/erigon/cl/merkle_tree" "github.com/ledgerwatch/erigon/cl/utils" @@ -285,14 +286,8 @@ func (s *SyncCommittee) Equal(s2 *SyncCommittee) bool { // Validator, contains if we were on bellatrix/alteir/phase0 and transition epoch. type Validator struct { - PublicKey [48]byte - WithdrawalCredentials libcommon.Hash - EffectiveBalance uint64 - Slashed bool - ActivationEligibilityEpoch uint64 - ActivationEpoch uint64 - ExitEpoch uint64 - WithdrawableEpoch uint64 + solid.Validator + // This is all stuff used by phase0 state transition. It makes many operations faster. // Source attesters IsCurrentMatchingSourceAttester bool @@ -310,7 +305,7 @@ type Validator struct { // DutiesAttested returns how many of its duties the validator attested and missed func (v *Validator) DutiesAttested() (attested, missed uint64) { - if v.Slashed { + if v.Slashed() { return 0, 3 } if v.IsPreviousMatchingSourceAttester { @@ -326,80 +321,41 @@ func (v *Validator) DutiesAttested() (attested, missed uint64) { return } func (v *Validator) IsSlashable(epoch uint64) bool { - return !v.Slashed && (v.ActivationEpoch <= epoch) && (epoch < v.WithdrawableEpoch) + return !v.Slashed() && (v.ActivationEpoch() <= epoch) && (epoch < v.WithdrawableEpoch()) } func (v *Validator) EncodeSSZ(dst []byte) ([]byte, error) { - buf := dst - buf = append(buf, v.PublicKey[:]...) - buf = append(buf, v.WithdrawalCredentials[:]...) - buf = append(buf, ssz.Uint64SSZ(v.EffectiveBalance)...) - buf = append(buf, ssz.BoolSSZ(v.Slashed)) - buf = append(buf, ssz.Uint64SSZ(v.ActivationEligibilityEpoch)...) - buf = append(buf, ssz.Uint64SSZ(v.ActivationEpoch)...) - buf = append(buf, ssz.Uint64SSZ(v.ExitEpoch)...) - buf = append(buf, ssz.Uint64SSZ(v.WithdrawableEpoch)...) - return buf, nil + return v.Validator.EncodeSSZ(dst), nil } func (v *Validator) DecodeSSZ(buf []byte, _ int) error { - if len(buf) < v.EncodingSizeSSZ() { - return fmt.Errorf("[Validator] err: %s", ssz.ErrLowBufferSize) - } - copy(v.PublicKey[:], buf) - copy(v.WithdrawalCredentials[:], buf[48:]) - v.EffectiveBalance = ssz.UnmarshalUint64SSZ(buf[80:]) - v.Slashed = buf[88] == 1 - v.ActivationEligibilityEpoch = ssz.UnmarshalUint64SSZ(buf[89:]) - v.ActivationEpoch = ssz.UnmarshalUint64SSZ(buf[97:]) - v.ExitEpoch = ssz.UnmarshalUint64SSZ(buf[105:]) - v.WithdrawableEpoch = ssz.UnmarshalUint64SSZ(buf[113:]) - return nil -} - -func (v *Validator) EncodingSizeSSZ() int { - return 121 + return v.Validator.DecodeSSZ(buf, 0) } var validatorLeavesPool = sync.Pool{ New: func() any { - o := make([][32]byte, 8) - return &o + p := make([]byte, 8*32) + return &p }, } -func (v *Validator) HashSSZ() ([32]byte, error) { - leavesp, _ := validatorLeavesPool.Get().(*[][32]byte) +func (v *Validator) HashSSZ() (o [32]byte, err error) { + leavesp, _ := validatorLeavesPool.Get().(*[]byte) leaves := *leavesp defer func() { - leaves = leaves[:8] validatorLeavesPool.Put(leavesp) }() - var ( - err error - ) - leaves[0], err = merkle_tree.PublicKeyRoot(v.PublicKey) - if err != nil { - return [32]byte{}, err - } - leaves[1] = v.WithdrawalCredentials - leaves[2] = merkle_tree.Uint64Root(v.EffectiveBalance) - leaves[3] = merkle_tree.BoolRoot(v.Slashed) - leaves[4] = merkle_tree.Uint64Root(v.ActivationEligibilityEpoch) - leaves[5] = merkle_tree.Uint64Root(v.ActivationEpoch) - leaves[6] = merkle_tree.Uint64Root(v.ExitEpoch) - leaves[7] = merkle_tree.Uint64Root(v.WithdrawableEpoch) - leaves = leaves[:8] - output, err := merkle_tree.ArraysRoot(leaves, 8) - return output, err + v.CopyHashBufferTo(leaves) + leaves = leaves[:(8 * 32)] + err = solid.TreeHashFlatSlice(leaves, o[:]) + return } // Active returns if validator is active for given epoch func (v *Validator) Active(epoch uint64) bool { - return v.ActivationEpoch <= epoch && epoch < v.ExitEpoch + return v.ActivationEpoch() <= epoch && epoch < v.ExitEpoch() } -func (v *Validator) Copy() *Validator { - copied := *v - return &copied +func (v *Validator) CopyTo(target *Validator) { + v.Validator.CopyTo(&target.Validator) } diff --git a/cl/merkle_tree/hasher.go b/cl/merkle_tree/hasher.go index 9180ead3e26..628b6c9db7e 100644 --- a/cl/merkle_tree/hasher.go +++ b/cl/merkle_tree/hasher.go @@ -15,14 +15,16 @@ const initialBufferSize = 0 // it is whatever // merkleHasher is used internally to provide shared buffer internally to the merkle_tree package. type merkleHasher struct { // internalBuffer is the shared buffer we use for each operation - internalBuffer [][32]byte + internalBuffer [][32]byte + internalFlatBuffer []byte // mu is the lock to ensure thread safety mu sync.Mutex } func newMerkleHasher() *merkleHasher { return &merkleHasher{ - internalBuffer: make([][32]byte, initialBufferSize), + internalBuffer: make([][32]byte, initialBufferSize), + internalFlatBuffer: make([]byte, initialBufferSize*32), } } @@ -43,6 +45,21 @@ func (m *merkleHasher) merkleizeTrieLeaves(leaves [][32]byte) ([32]byte, error) return leaves[0], nil } +// merkleizeTrieLeaves returns intermediate roots of given leaves. +func (m *merkleHasher) merkleizeTrieLeavesFlat(leaves []byte, out []byte) (err error) { + m.mu.Lock() + defer m.mu.Unlock() + layer := m.getFlatBuffer(len(leaves) / 2) + for len(leaves) > 32 { + if err := gohashtree.HashByteSlice(layer, leaves); err != nil { + return err + } + leaves = layer[:len(leaves)/2] + } + copy(out, leaves[:32]) + return +} + // getBuffer provides buffer of given size. func (m *merkleHasher) getBuffer(size int) [][32]byte { if size > len(m.internalBuffer) { @@ -50,3 +67,11 @@ func (m *merkleHasher) getBuffer(size int) [][32]byte { } return m.internalBuffer[:size] } + +// getBuffer provides buffer of given size. +func (m *merkleHasher) getFlatBuffer(size int) []byte { + if size > len(m.internalFlatBuffer) { + m.internalFlatBuffer = make([]byte, size) + } + return m.internalFlatBuffer[:size] +} diff --git a/cl/merkle_tree/merkle_root.go b/cl/merkle_tree/merkle_root.go index 0676f4cddd5..6ab2d05b15e 100644 --- a/cl/merkle_tree/merkle_root.go +++ b/cl/merkle_tree/merkle_root.go @@ -15,6 +15,14 @@ func MerkleRootFromLeaves(leaves [][32]byte) ([32]byte, error) { return globalHasher.merkleizeTrieLeaves(hashLayer) } +func MerkleRootFromFlatLeaves(leaves []byte, out []byte) (err error) { + if len(leaves) <= 32 { + copy(out, leaves) + return + } + return globalHasher.merkleizeTrieLeavesFlat(leaves, out) +} + // getDepth returns the depth of a merkle tree with a given number of nodes. // The depth is defined as the number of levels in the tree, with the root // node at level 0 and each child node at a level one greater than its parent. diff --git a/cl/merkle_tree/primitives.go b/cl/merkle_tree/primitives.go index 38157011d0f..b8d46cc5b1c 100644 --- a/cl/merkle_tree/primitives.go +++ b/cl/merkle_tree/primitives.go @@ -36,3 +36,12 @@ func PublicKeyRoot(key [48]byte) (libcommon.Hash, error) { lastByte, }, 2) } + +func InPlacePublicKeyRoot(key []byte) error { + err := MerkleRootFromFlatLeaves(key, key) + if err != nil { + return err + } + key = key[:32] + return nil +} diff --git a/cmd/erigon-cl/core/state/accessors.go b/cmd/erigon-cl/core/state/accessors.go index 680ecba4671..6745db671ea 100644 --- a/cmd/erigon-cl/core/state/accessors.go +++ b/cmd/erigon-cl/core/state/accessors.go @@ -86,7 +86,7 @@ func IsUnslashedParticipatingIndex(b *raw.BeaconState, epoch, index uint64, flag if err != nil { return false } - return validator.Active(epoch) && b.EpochParticipation(false)[index].HasFlag(flagIdx) && !validator.Slashed + return validator.Active(epoch) && b.EpochParticipation(false)[index].HasFlag(flagIdx) && !validator.Slashed() } // EligibleValidatorsIndicies Implementation of get_eligible_validator_indices as defined in the eth 2.0 specs. @@ -95,7 +95,7 @@ func EligibleValidatorsIndicies(b *raw.BeaconState) (eligibleValidators []uint64 previousEpoch := PreviousEpoch(b) b.ForEachValidator(func(validator *cltypes.Validator, i, total int) bool { - if validator.Active(previousEpoch) || (validator.Slashed && previousEpoch+1 < validator.WithdrawableEpoch) { + if validator.Active(previousEpoch) || (validator.Slashed() && previousEpoch+1 < validator.WithdrawableEpoch()) { eligibleValidators = append(eligibleValidators, uint64(i)) } return true @@ -115,7 +115,8 @@ func IsValidIndexedAttestation(b *raw.BeaconState, att *cltypes.IndexedAttestati if err != nil { return false, err } - pks = append(pks, val.PublicKey[:]) + pk := val.PublicKey() + pks = append(pks, pk[:]) } domain, err := b.GetDomain(b.BeaconConfig().DomainBeaconAttester, att.Data.Target.Epoch) @@ -154,7 +155,7 @@ func GetUnslashedParticipatingIndices(b *raw.BeaconState, flagIndex int, epoch u b.ForEachValidator(func(validator *cltypes.Validator, i, total int) bool { if !validator.Active(epoch) || !participation[i].HasFlag(flagIndex) || - validator.Slashed { + validator.Slashed() { return true } validatorSet = append(validatorSet, uint64(i)) @@ -165,14 +166,14 @@ func GetUnslashedParticipatingIndices(b *raw.BeaconState, flagIndex int, epoch u // Implementation of is_eligible_for_activation_queue. Specs at: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#is_eligible_for_activation_queue func IsValidatorEligibleForActivationQueue(b *raw.BeaconState, validator *cltypes.Validator) bool { - return validator.ActivationEligibilityEpoch == b.BeaconConfig().FarFutureEpoch && - validator.EffectiveBalance == b.BeaconConfig().MaxEffectiveBalance + return validator.ActivationEligibilityEpoch() == b.BeaconConfig().FarFutureEpoch && + validator.EffectiveBalance() == b.BeaconConfig().MaxEffectiveBalance } // Implementation of is_eligible_for_activation. Specs at: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#is_eligible_for_activation func IsValidatorEligibleForActivation(b *raw.BeaconState, validator *cltypes.Validator) bool { - return validator.ActivationEligibilityEpoch <= b.FinalizedCheckpoint().Epoch && - validator.ActivationEpoch == b.BeaconConfig().FarFutureEpoch + return validator.ActivationEligibilityEpoch() <= b.FinalizedCheckpoint().Epoch && + validator.ActivationEpoch() == b.BeaconConfig().FarFutureEpoch } // Check whether a merge transition is complete by verifying the presence of a valid execution payload header. @@ -204,14 +205,14 @@ func ExpectedWithdrawals(b *raw.BeaconState) []*types.Withdrawal { // supposedly this operation is safe because we checked the validator length about currentValidator, _ := b.ValidatorForValidatorIndex(int(nextWithdrawalValidatorIndex)) currentBalance, _ := b.ValidatorBalance(int(nextWithdrawalValidatorIndex)) - + wd := currentValidator.WithdrawalCredentials() // Check if the validator is fully withdrawable if isFullyWithdrawableValidator(b.BeaconConfig(), currentValidator, currentBalance, currentEpoch) { // Add a new withdrawal with the validator's withdrawal credentials and balance newWithdrawal := &types.Withdrawal{ Index: nextWithdrawalIndex, Validator: nextWithdrawalValidatorIndex, - Address: libcommon.BytesToAddress(currentValidator.WithdrawalCredentials[12:]), + Address: libcommon.BytesToAddress(wd[12:]), Amount: currentBalance, } withdrawals = append(withdrawals, newWithdrawal) @@ -221,7 +222,7 @@ func ExpectedWithdrawals(b *raw.BeaconState) []*types.Withdrawal { newWithdrawal := &types.Withdrawal{ Index: nextWithdrawalIndex, Validator: nextWithdrawalValidatorIndex, - Address: libcommon.BytesToAddress(currentValidator.WithdrawalCredentials[12:]), + Address: libcommon.BytesToAddress(wd[12:]), Amount: currentBalance - b.BeaconConfig().MaxEffectiveBalance, } withdrawals = append(withdrawals, newWithdrawal) diff --git a/cmd/erigon-cl/core/state/accessors_test.go b/cmd/erigon-cl/core/state/accessors_test.go index 3d1a2e3922e..2c3f7e88c2c 100644 --- a/cmd/erigon-cl/core/state/accessors_test.go +++ b/cmd/erigon-cl/core/state/accessors_test.go @@ -17,10 +17,10 @@ func getTestState(t *testing.T) *state.BeaconState { numVals := 2048 validators := make([]*cltypes.Validator, numVals) for i := 0; i < numVals; i++ { - validators[i] = &cltypes.Validator{ - ActivationEpoch: 0, - ExitEpoch: 10000, - } + v := &cltypes.Validator{} + validators[i] = v + v.SetActivationEpoch(0) + v.SetExitEpoch(10000) } b := state.GetEmptyBeaconState() b.SetValidators(validators) @@ -50,10 +50,10 @@ func TestGetBeaconProposerIndex(t *testing.T) { numVals := 2048 validators := make([]*cltypes.Validator, numVals) for i := 0; i < numVals; i++ { - validators[i] = &cltypes.Validator{ - ActivationEpoch: 0, - ExitEpoch: 10000, - } + v := &cltypes.Validator{} + validators[i] = v + v.SetActivationEpoch(0) + v.SetExitEpoch(10000) } testCases := []struct { description string @@ -137,7 +137,11 @@ func TestComputeShuffledIndex(t *testing.T) { func generateBeaconStateWithValidators(n int) *state.BeaconState { b := state.GetEmptyBeaconState() for i := 0; i < n; i++ { - b.AddValidator(&cltypes.Validator{EffectiveBalance: clparams.MainnetBeaconConfig.MaxEffectiveBalance}, clparams.MainnetBeaconConfig.MaxEffectiveBalance) + v := &cltypes.Validator{} + v.SetActivationEpoch(0) + v.SetExitEpoch(10000) + v.SetEffectiveBalance(clparams.MainnetBeaconConfig.MaxEffectiveBalance) + b.AddValidator(v, clparams.MainnetBeaconConfig.MaxEffectiveBalance) } return b } @@ -204,7 +208,12 @@ func TestComputeProposerIndex(t *testing.T) { func TestSyncReward(t *testing.T) { s := state.GetEmptyBeaconState() - s.AddValidator(&cltypes.Validator{EffectiveBalance: 3099999999909, ExitEpoch: 2}, 3099999999909) + + v := &cltypes.Validator{} + v.SetActivationEpoch(0) + v.SetExitEpoch(2) + v.SetEffectiveBalance(3099999999909) + s.AddValidator(v, 3099999999909) propReward, partRew, err := s.SyncRewards() require.NoError(t, err) require.Equal(t, propReward, uint64(30)) @@ -220,10 +229,10 @@ func TestComputeCommittee(t *testing.T) { for i := 0; i < len(validators); i++ { var k [48]byte copy(k[:], strconv.Itoa(i)) - validators[i] = &cltypes.Validator{ - PublicKey: k, - ExitEpoch: clparams.MainnetBeaconConfig.FarFutureEpoch, - } + v := &cltypes.Validator{} + v.SetExitEpoch(clparams.MainnetBeaconConfig.FarFutureEpoch) + v.SetPublicKey(k) + validators[i] = v } bState := state.GetEmptyBeaconState() bState.SetValidators(validators) diff --git a/cmd/erigon-cl/core/state/cache.go b/cmd/erigon-cl/core/state/cache.go index daededed648..b7d8f0fe5e0 100644 --- a/cmd/erigon-cl/core/state/cache.go +++ b/cmd/erigon-cl/core/state/cache.go @@ -184,7 +184,7 @@ func (b *BeaconState) _refreshActiveBalances() { *b.totalActiveBalanceCache = 0 b.ForEachValidator(func(validator *cltypes.Validator, idx, total int) bool { if validator.Active(epoch) { - *b.totalActiveBalanceCache += validator.EffectiveBalance + *b.totalActiveBalanceCache += validator.EffectiveBalance() } return true }) @@ -212,7 +212,7 @@ func (b *BeaconState) initBeaconState() error { b.publicKeyIndicies = make(map[[48]byte]uint64) b.ForEachValidator(func(validator *cltypes.Validator, i, total int) bool { - b.publicKeyIndicies[validator.PublicKey] = uint64(i) + b.publicKeyIndicies[validator.PublicKey()] = uint64(i) return true }) diff --git a/cmd/erigon-cl/core/state/cache_accessors.go b/cmd/erigon-cl/core/state/cache_accessors.go index 9af55563e8b..caf0ea8e872 100644 --- a/cmd/erigon-cl/core/state/cache_accessors.go +++ b/cmd/erigon-cl/core/state/cache_accessors.go @@ -190,7 +190,14 @@ func (b *BeaconState) ComputeNextSyncCommittee() (*cltypes.SyncCommittee, error) syncCommitteePubKeys := make([][48]byte, 0, cltypes.SyncCommitteeSize) preInputs := shuffling.ComputeShuffledIndexPreInputs(b.BeaconConfig(), seed) for len(syncCommitteePubKeys) < cltypes.SyncCommitteeSize { - shuffledIndex, err := shuffling.ComputeShuffledIndex(b.BeaconConfig(), i%activeValidatorCount, activeValidatorCount, seed, preInputs, optimizedHashFunc) + shuffledIndex, err := shuffling.ComputeShuffledIndex( + b.BeaconConfig(), + i%activeValidatorCount, + activeValidatorCount, + seed, + preInputs, + optimizedHashFunc, + ) if err != nil { return nil, err } @@ -205,8 +212,8 @@ func (b *BeaconState) ComputeNextSyncCommittee() (*cltypes.SyncCommittee, error) if err != nil { return nil, err } - if validator.EffectiveBalance*math.MaxUint8 >= beaconConfig.MaxEffectiveBalance*randomByte { - syncCommitteePubKeys = append(syncCommitteePubKeys, validator.PublicKey) + if validator.EffectiveBalance()*math.MaxUint8 >= beaconConfig.MaxEffectiveBalance*randomByte { + syncCommitteePubKeys = append(syncCommitteePubKeys, validator.PublicKey()) } i++ } diff --git a/cmd/erigon-cl/core/state/cache_mutators.go b/cmd/erigon-cl/core/state/cache_mutators.go index 4367fb65ede..f4cfd43e3d3 100644 --- a/cmd/erigon-cl/core/state/cache_mutators.go +++ b/cmd/erigon-cl/core/state/cache_mutators.go @@ -80,15 +80,15 @@ func (b *BeaconState) InitiateValidatorExit(index uint64) error { currentEpoch := Epoch(b.BeaconState) exitQueueEpoch := ComputeActivationExitEpoch(b.BeaconConfig(), currentEpoch) b.ForEachValidator(func(v *cltypes.Validator, idx, total int) bool { - if v.ExitEpoch != b.BeaconConfig().FarFutureEpoch && v.ExitEpoch > exitQueueEpoch { - exitQueueEpoch = v.ExitEpoch + if v.ExitEpoch() != b.BeaconConfig().FarFutureEpoch && v.ExitEpoch() > exitQueueEpoch { + exitQueueEpoch = v.ExitEpoch() } return true }) exitQueueChurn := 0 b.ForEachValidator(func(v *cltypes.Validator, idx, total int) bool { - if v.ExitEpoch == exitQueueEpoch { + if v.ExitEpoch() == exitQueueEpoch { exitQueueChurn += 1 } return true diff --git a/cmd/erigon-cl/core/state/cache_setters.go b/cmd/erigon-cl/core/state/cache_setters.go index 69083752368..a1129d9594c 100644 --- a/cmd/erigon-cl/core/state/cache_setters.go +++ b/cmd/erigon-cl/core/state/cache_setters.go @@ -16,7 +16,7 @@ func (b *BeaconState) SetSlot(slot uint64) { func (b *BeaconState) AddValidator(validator *cltypes.Validator, balance uint64) { b.BeaconState.AddValidator(validator, balance) - b.publicKeyIndicies[validator.PublicKey] = uint64(b.ValidatorLength()) - 1 + b.publicKeyIndicies[validator.PublicKey()] = uint64(b.ValidatorLength()) - 1 // change in validator set means cache purging b.totalActiveBalanceCache = nil } diff --git a/cmd/erigon-cl/core/state/copy.go b/cmd/erigon-cl/core/state/copy.go index ea41bf23d78..0a7cf9d1c7d 100644 --- a/cmd/erigon-cl/core/state/copy.go +++ b/cmd/erigon-cl/core/state/copy.go @@ -24,17 +24,19 @@ func (b *BeaconState) copyCachesInto(bs *BeaconState) error { if b.Version() == clparams.Phase0Version { return bs.initBeaconState() } - bs.publicKeyIndicies = make(map[[48]byte]uint64) + if bs.publicKeyIndicies == nil { + bs.publicKeyIndicies = make(map[[48]byte]uint64) + } + for k := range bs.publicKeyIndicies { + delete(bs.publicKeyIndicies, k) + } for pk, index := range b.publicKeyIndicies { bs.publicKeyIndicies[pk] = index } // Sync caches - if err := bs.initCaches(); err != nil { - return err - } - copyLRU(bs.activeValidatorsCache, b.activeValidatorsCache) - copyLRU(bs.shuffledSetsCache, b.shuffledSetsCache) - copyLRU(bs.committeeCache, b.committeeCache) + bs.activeValidatorsCache = copyLRU(bs.activeValidatorsCache, b.activeValidatorsCache) + bs.shuffledSetsCache = copyLRU(bs.shuffledSetsCache, b.shuffledSetsCache) + bs.committeeCache = copyLRU(bs.committeeCache, b.committeeCache) if b.totalActiveBalanceCache != nil { bs.totalActiveBalanceCache = new(uint64) diff --git a/cmd/erigon-cl/core/state/mutators_test.go b/cmd/erigon-cl/core/state/mutators_test.go index 7c04ad35ea8..6b71dc822ab 100644 --- a/cmd/erigon-cl/core/state/mutators_test.go +++ b/cmd/erigon-cl/core/state/mutators_test.go @@ -17,7 +17,9 @@ func getTestStateBalances(t *testing.T) *state.BeaconState { numVals := uint64(2048) b := state.GetEmptyBeaconState() for i := uint64(0); i < numVals; i++ { - b.AddValidator(&cltypes.Validator{ExitEpoch: clparams.MainnetBeaconConfig.FarFutureEpoch}, i) + v := &cltypes.Validator{} + v.SetExitEpoch(clparams.MainnetBeaconConfig.FarFutureEpoch) + b.AddValidator(v, i) } return b } @@ -25,10 +27,10 @@ func getTestStateBalances(t *testing.T) *state.BeaconState { func getTestStateValidators(t *testing.T, numVals int) *state.BeaconState { validators := make([]*cltypes.Validator, numVals) for i := 0; i < numVals; i++ { - validators[i] = &cltypes.Validator{ - ActivationEpoch: 0, - ExitEpoch: testExitEpoch, - } + v := &cltypes.Validator{} + v.SetActivationEpoch(0) + v.SetExitEpoch(testExitEpoch) + validators[i] = v } b := state.GetEmptyBeaconState() b.SetSlot(testExitEpoch * clparams.MainnetBeaconConfig.SlotsPerEpoch) @@ -40,16 +42,16 @@ func TestIncreaseBalance(t *testing.T) { s := getTestStateBalances(t) testInd := uint64(42) amount := uint64(100) - beforeBalance := s.Balances()[testInd] + beforeBalance, _ := s.ValidatorBalance(int(testInd)) state.IncreaseBalance(s.BeaconState, testInd, amount) - afterBalance := s.Balances()[testInd] + afterBalance, _ := s.ValidatorBalance(int(testInd)) require.Equal(t, afterBalance, beforeBalance+amount) } func TestDecreaseBalance(t *testing.T) { sampleState := getTestStateBalances(t) testInd := uint64(42) - beforeBalance := sampleState.Balances()[testInd] + beforeBalance, _ := sampleState.ValidatorBalance(int(testInd)) testCases := []struct { description string @@ -77,13 +79,21 @@ func TestDecreaseBalance(t *testing.T) { t.Run(tc.description, func(t *testing.T) { s := getTestStateBalances(t) require.NoError(t, state.DecreaseBalance(s.BeaconState, testInd, tc.delta)) - afterBalance := s.Balances()[testInd] + afterBalance, _ := s.ValidatorBalance(int(testInd)) require.Equal(t, afterBalance, tc.expectedBalance) }) } } func TestInitiatieValidatorExit(t *testing.T) { + + v1 := &cltypes.Validator{} + v1.SetExitEpoch(clparams.MainnetBeaconConfig.FarFutureEpoch) + v1.SetActivationEpoch(0) + v2 := &cltypes.Validator{} + v2.SetExitEpoch(testExitEpoch) + v2.SetWithdrawableEpoch(testExitEpoch + clparams.MainnetBeaconConfig.MinValidatorWithdrawabilityDelay) + v2.SetActivationEpoch(0) testCases := []struct { description string numValidators uint64 @@ -96,36 +106,29 @@ func TestInitiatieValidatorExit(t *testing.T) { numValidators: 3, expectedExitEpoch: 58, expectedWithdrawlableEpoch: 314, - validator: &cltypes.Validator{ - ExitEpoch: clparams.MainnetBeaconConfig.FarFutureEpoch, - ActivationEpoch: 0, - }, + validator: v1, }, { description: "exit_epoch_set", numValidators: 3, expectedExitEpoch: testExitEpoch, expectedWithdrawlableEpoch: testExitEpoch + clparams.MainnetBeaconConfig.MinValidatorWithdrawabilityDelay, - validator: &cltypes.Validator{ - ExitEpoch: testExitEpoch, - WithdrawableEpoch: testExitEpoch + clparams.MainnetBeaconConfig.MinValidatorWithdrawabilityDelay, - ActivationEpoch: 0, - }, + validator: v2, }, } for _, tc := range testCases { t.Run(tc.description, func(t *testing.T) { state := getTestStateValidators(t, int(tc.numValidators)) - state.SetValidators(append(state.Validators(), tc.validator)) - testInd := uint64(len(state.Validators()) - 1) + state.AppendValidator(tc.validator) + testInd := uint64(state.ValidatorLength() - 1) state.InitiateValidatorExit(testInd) val, err := state.ValidatorForValidatorIndex(int(testInd)) require.NoError(t, err) - if val.ExitEpoch != tc.expectedExitEpoch { - t.Errorf("unexpected exit epoch: got %d, want %d", val.ExitEpoch, tc.expectedExitEpoch) + if val.ExitEpoch() != tc.expectedExitEpoch { + t.Errorf("unexpected exit epoch: got %d, want %d", val.ExitEpoch(), tc.expectedExitEpoch) } - if val.WithdrawableEpoch != tc.expectedWithdrawlableEpoch { - t.Errorf("unexpected withdrawable epoch: got %d, want %d", val.WithdrawableEpoch, tc.expectedWithdrawlableEpoch) + if val.WithdrawableEpoch() != tc.expectedWithdrawlableEpoch { + t.Errorf("unexpected withdrawable epoch: got %d, want %d", val.WithdrawableEpoch(), tc.expectedWithdrawlableEpoch) } }) } @@ -138,18 +141,18 @@ func TestSlashValidator(t *testing.T) { successState := getTestState(t) successBalances := []uint64{} - for i := 0; i < len(successState.Validators()); i++ { + for i := 0; i < successState.ValidatorLength(); i++ { successBalances = append(successBalances, uint64(i+1)) } successState.SetBalances(successBalances) // Set up slashed balance. preSlashBalance := uint64(1 << 20) - successState.Balances()[slashedInd] = preSlashBalance + successState.SetValidatorBalance(slashedInd, preSlashBalance) vali, err := successState.ValidatorForValidatorIndex(slashedInd) require.NoError(t, err) successState.SetValidatorAtIndex(slashedInd, vali) - vali.EffectiveBalance = preSlashBalance + vali.SetEffectiveBalance(preSlashBalance) testCases := []struct { description string @@ -180,7 +183,7 @@ func TestSlashValidator(t *testing.T) { vali, err := tc.state.ValidatorForValidatorIndex(slashedInd) require.NoError(t, err) // Check that the validator is slashed. - if !vali.Slashed { + if !vali.Slashed() { t.Errorf("slashed index validator not set as slashed") } }) diff --git a/cmd/erigon-cl/core/state/raw/copy.go b/cmd/erigon-cl/core/state/raw/copy.go index d556eb8c5de..36c2ea14863 100644 --- a/cmd/erigon-cl/core/state/raw/copy.go +++ b/cmd/erigon-cl/core/state/raw/copy.go @@ -24,21 +24,15 @@ func (b *BeaconState) CopyInto(dst *BeaconState) error { dst.eth1DepositIndex = b.eth1DepositIndex for i, validator := range b.validators { if i >= len(dst.validators) { - dst.validators = append(dst.validators, validator.Copy()) + nv := &cltypes.Validator{} + validator.CopyTo(nv) + dst.validators = append(dst.validators, nv) continue } - copy(dst.validators[i].WithdrawalCredentials[:], validator.WithdrawalCredentials[:]) - copy(dst.validators[i].PublicKey[:], validator.PublicKey[:]) - dst.validators[i].ActivationEligibilityEpoch = validator.ActivationEligibilityEpoch - dst.validators[i].ActivationEpoch = validator.ActivationEpoch - dst.validators[i].ExitEpoch = validator.ExitEpoch - dst.validators[i].EffectiveBalance = validator.EffectiveBalance - dst.validators[i].Slashed = validator.Slashed - dst.validators[i].WithdrawableEpoch = validator.WithdrawableEpoch + validator.CopyTo(dst.validators[i]) } dst.validators = dst.validators[:len(b.validators)] - dst.balances = make([]uint64, len(b.balances)) - copy(dst.balances, b.balances) + b.balances.CopyTo(dst.balances) copy(dst.randaoMixes[:], b.randaoMixes[:]) copy(dst.slashings[:], b.slashings[:]) dst.previousEpochParticipation = b.previousEpochParticipation.Copy() @@ -47,12 +41,12 @@ func (b *BeaconState) CopyInto(dst *BeaconState) error { dst.currentJustifiedCheckpoint = b.currentJustifiedCheckpoint.Copy() dst.previousJustifiedCheckpoint = b.previousJustifiedCheckpoint.Copy() if b.version == clparams.Phase0Version { - return dst.init() + dst.init() + return nil } dst.currentSyncCommittee = b.currentSyncCommittee.Copy() dst.nextSyncCommittee = b.nextSyncCommittee.Copy() - dst.inactivityScores = make([]uint64, len(b.inactivityScores)) - copy(dst.inactivityScores, b.inactivityScores) + b.inactivityScores.CopyTo(dst.inactivityScores) dst.justificationBits = b.justificationBits.Copy() if b.version >= clparams.BellatrixVersion { diff --git a/cmd/erigon-cl/core/state/raw/getters.go b/cmd/erigon-cl/core/state/raw/getters.go index 9ac07c3a77a..c9eecf34a34 100644 --- a/cmd/erigon-cl/core/state/raw/getters.go +++ b/cmd/erigon-cl/core/state/raw/getters.go @@ -75,13 +75,12 @@ func (b *BeaconState) Eth1DepositIndex() uint64 { return b.eth1DepositIndex } -func (b *BeaconState) Validators() []*cltypes.Validator { - return b.validators -} - func (b *BeaconState) ValidatorLength() int { return len(b.validators) } +func (b *BeaconState) AppendValidator(in *cltypes.Validator) { + b.validators = append(b.validators, in) +} func (b *BeaconState) ForEachValidator(fn func(v *cltypes.Validator, idx int, total int) bool) { for idx, v := range b.validators { @@ -99,36 +98,32 @@ func (b *BeaconState) ValidatorForValidatorIndex(index int) (*cltypes.Validator, return b.validators[index], nil } -func (b *BeaconState) Balances() []uint64 { - return b.balances -} - func (b *BeaconState) ValidatorBalance(index int) (uint64, error) { - if index >= len(b.balances) { + if index >= b.balances.Length() { return 0, ErrInvalidValidatorIndex } - return b.balances[index], nil + return b.balances.Get(index), nil } func (b *BeaconState) ValidatorExitEpoch(index int) (uint64, error) { if index >= len(b.validators) { return 0, ErrInvalidValidatorIndex } - return b.validators[index].ExitEpoch, nil + return b.validators[index].ExitEpoch(), nil } func (b *BeaconState) ValidatorWithdrawableEpoch(index int) (uint64, error) { if index >= len(b.validators) { return 0, ErrInvalidValidatorIndex } - return b.validators[index].WithdrawableEpoch, nil + return b.validators[index].WithdrawableEpoch(), nil } func (b *BeaconState) ValidatorEffectiveBalance(index int) (uint64, error) { if index >= len(b.validators) { return 0, ErrInvalidValidatorIndex } - return b.validators[index].EffectiveBalance, nil + return b.validators[index].EffectiveBalance(), nil } func (b *BeaconState) ValidatorMinCurrentInclusionDelayAttestation(index int) (*cltypes.PendingAttestation, error) { @@ -196,15 +191,11 @@ func (b *BeaconState) CurrentJustifiedCheckpoint() *cltypes.Checkpoint { return b.currentJustifiedCheckpoint } -func (b *BeaconState) InactivityScores() []uint64 { - return b.inactivityScores -} - func (b *BeaconState) ValidatorInactivityScore(index int) (uint64, error) { - if len(b.inactivityScores) <= index { + if b.inactivityScores.Length() <= index { return 0, ErrInvalidValidatorIndex } - return b.inactivityScores[index], nil + return b.inactivityScores.Get(index), nil } func (b *BeaconState) FinalizedCheckpoint() *cltypes.Checkpoint { @@ -261,7 +252,7 @@ func (b *BeaconState) GetBlockRootAtSlot(slot uint64) (libcommon.Hash, error) { return b.blockRoots[slot%b.BeaconConfig().SlotsPerHistoricalRoot], nil } -// GetBl +// GetDomain func (b *BeaconState) GetDomain(domainType [4]byte, epoch uint64) ([]byte, error) { if epoch < b.fork.Epoch { return fork.ComputeDomain(domainType[:], b.fork.PreviousVersion, b.genesisValidatorsRoot) diff --git a/cmd/erigon-cl/core/state/raw/hashing.go b/cmd/erigon-cl/core/state/raw/hashing.go index 60996358882..ecc44459e59 100644 --- a/cmd/erigon-cl/core/state/raw/hashing.go +++ b/cmd/erigon-cl/core/state/raw/hashing.go @@ -130,10 +130,8 @@ func (b *BeaconState) computeDirtyLeaves() error { // Field(12): Balances if b.isLeafDirty(BalancesLeafIndex) { - root, err := merkle_tree.Uint64ListRootWithLimit(b.balances, state_encoding.ValidatorLimitForBalancesChunks()) - if err != nil { - return err - } + root := [32]byte{} + b.balances.HashSSZTo(root[:]) b.updateLeaf(BalancesLeafIndex, root) } @@ -226,10 +224,8 @@ func (b *BeaconState) computeDirtyLeaves() error { } // Field(21): Inactivity Scores if b.isLeafDirty(InactivityScoresLeafIndex) { - root, err := merkle_tree.Uint64ListRootWithLimit(b.inactivityScores, state_encoding.ValidatorLimitForBalancesChunks()) - if err != nil { - return err - } + root := [32]byte{} + b.inactivityScores.HashSSZTo(root[:]) b.updateLeaf(InactivityScoresLeafIndex, root) } diff --git a/cmd/erigon-cl/core/state/raw/setters.go b/cmd/erigon-cl/core/state/raw/setters.go index 7afd32cced8..965e7a260e5 100644 --- a/cmd/erigon-cl/core/state/raw/setters.go +++ b/cmd/erigon-cl/core/state/raw/setters.go @@ -42,32 +42,32 @@ func (b *BeaconState) SetHistoricalRootAt(index int, root [32]byte) { func (b *BeaconState) SetWithdrawalCredentialForValidatorAtIndex(index int, creds libcommon.Hash) { b.markLeaf(ValidatorsLeafIndex) - b.validators[index].WithdrawalCredentials = creds + b.validators[index].SetWithdrawalCredentials(creds) } func (b *BeaconState) SetExitEpochForValidatorAtIndex(index int, epoch uint64) { b.markLeaf(ValidatorsLeafIndex) - b.validators[index].ExitEpoch = epoch + b.validators[index].SetExitEpoch(epoch) } func (b *BeaconState) SetWithdrawableEpochForValidatorAtIndex(index int, epoch uint64) { b.markLeaf(ValidatorsLeafIndex) - b.validators[index].WithdrawableEpoch = epoch + b.validators[index].SetWithdrawableEpoch(epoch) } func (b *BeaconState) SetEffectiveBalanceForValidatorAtIndex(index int, balance uint64) { b.markLeaf(ValidatorsLeafIndex) - b.validators[index].EffectiveBalance = balance + b.validators[index].SetEffectiveBalance(balance) } func (b *BeaconState) SetActivationEpochForValidatorAtIndex(index int, epoch uint64) { b.markLeaf(ValidatorsLeafIndex) - b.validators[index].ActivationEpoch = epoch + b.validators[index].SetActivationEpoch(epoch) } func (b *BeaconState) SetActivationEligibilityEpochForValidatorAtIndex(index int, epoch uint64) { b.markLeaf(ValidatorsLeafIndex) - b.validators[index].ActivationEligibilityEpoch = epoch + b.validators[index].SetActivationEligibilityEpoch(epoch) } func (b *BeaconState) SetEth1Data(eth1Data *cltypes.Eth1Data) { @@ -91,24 +91,24 @@ func (b *BeaconState) SetEth1DepositIndex(eth1DepositIndex uint64) { } func (b *BeaconState) SetValidatorSlashed(index int, slashed bool) error { - if index >= len(b.balances) { + if index >= b.balances.Length() { return ErrInvalidValidatorIndex } b.markLeaf(ValidatorsLeafIndex) - b.validators[index].Slashed = slashed + b.validators[index].SetSlashed(slashed) return nil } func (b *BeaconState) SetValidatorWithdrawableEpoch(index int, epoch uint64) error { - if index >= len(b.balances) { + if index >= b.balances.Length() { return ErrInvalidValidatorIndex } b.markLeaf(ValidatorsLeafIndex) - b.validators[index].WithdrawableEpoch = epoch + b.validators[index].SetWithdrawableEpoch(epoch) return nil } func (b *BeaconState) SetValidatorMinCurrentInclusionDelayAttestation(index int, value *cltypes.PendingAttestation) error { - if index >= len(b.balances) { + if index >= b.balances.Length() { return ErrInvalidValidatorIndex } b.markLeaf(ValidatorsLeafIndex) @@ -116,7 +116,7 @@ func (b *BeaconState) SetValidatorMinCurrentInclusionDelayAttestation(index int, return nil } func (b *BeaconState) SetValidatorIsCurrentMatchingSourceAttester(index int, value bool) error { - if index >= len(b.balances) { + if index >= b.balances.Length() { return ErrInvalidValidatorIndex } b.markLeaf(ValidatorsLeafIndex) @@ -124,7 +124,7 @@ func (b *BeaconState) SetValidatorIsCurrentMatchingSourceAttester(index int, val return nil } func (b *BeaconState) SetValidatorIsCurrentMatchingTargetAttester(index int, value bool) error { - if index >= len(b.balances) { + if index >= b.balances.Length() { return ErrInvalidValidatorIndex } b.markLeaf(ValidatorsLeafIndex) @@ -132,7 +132,7 @@ func (b *BeaconState) SetValidatorIsCurrentMatchingTargetAttester(index int, val return nil } func (b *BeaconState) SetValidatorIsCurrentMatchingHeadAttester(index int, value bool) error { - if index >= len(b.balances) { + if index >= b.balances.Length() { return ErrInvalidValidatorIndex } b.markLeaf(ValidatorsLeafIndex) @@ -140,7 +140,7 @@ func (b *BeaconState) SetValidatorIsCurrentMatchingHeadAttester(index int, value return nil } func (b *BeaconState) SetValidatorMinPreviousInclusionDelayAttestation(index int, value *cltypes.PendingAttestation) error { - if index >= len(b.balances) { + if index >= b.balances.Length() { return ErrInvalidValidatorIndex } b.markLeaf(ValidatorsLeafIndex) @@ -148,7 +148,7 @@ func (b *BeaconState) SetValidatorMinPreviousInclusionDelayAttestation(index int return nil } func (b *BeaconState) SetValidatorIsPreviousMatchingSourceAttester(index int, value bool) error { - if index >= len(b.balances) { + if index >= b.balances.Length() { return ErrInvalidValidatorIndex } b.markLeaf(ValidatorsLeafIndex) @@ -156,7 +156,7 @@ func (b *BeaconState) SetValidatorIsPreviousMatchingSourceAttester(index int, va return nil } func (b *BeaconState) SetValidatorIsPreviousMatchingTargetAttester(index int, value bool) error { - if index >= len(b.balances) { + if index >= b.balances.Length() { return ErrInvalidValidatorIndex } b.markLeaf(ValidatorsLeafIndex) @@ -164,7 +164,7 @@ func (b *BeaconState) SetValidatorIsPreviousMatchingTargetAttester(index int, va return nil } func (b *BeaconState) SetValidatorIsPreviousMatchingHeadAttester(index int, value bool) error { - if index >= len(b.balances) { + if index >= b.balances.Length() { return ErrInvalidValidatorIndex } b.markLeaf(ValidatorsLeafIndex) @@ -173,11 +173,11 @@ func (b *BeaconState) SetValidatorIsPreviousMatchingHeadAttester(index int, valu } func (b *BeaconState) SetValidatorBalance(index int, balance uint64) error { - if index >= len(b.balances) { + if index >= b.balances.Length() { return ErrInvalidValidatorIndex } b.markLeaf(BalancesLeafIndex) - b.balances[index] = balance + b.balances.Set(index, balance) return nil } @@ -190,7 +190,7 @@ func (b *BeaconState) SetValidators(validators []*cltypes.Validator) error { func (b *BeaconState) AddValidator(validator *cltypes.Validator, balance uint64) { b.validators = append(b.validators, validator) - b.balances = append(b.balances, balance) + b.balances.Append(balance) b.markLeaf(ValidatorsLeafIndex) b.markLeaf(BalancesLeafIndex) @@ -198,7 +198,10 @@ func (b *BeaconState) AddValidator(validator *cltypes.Validator, balance uint64) func (b *BeaconState) SetBalances(balances []uint64) { b.markLeaf(BalancesLeafIndex) - b.balances = balances + b.balances.Clear() + for _, v := range balances { + b.balances.Append(v) + } } func (b *BeaconState) SetRandaoMixAt(index int, mix libcommon.Hash) { @@ -297,21 +300,24 @@ func (b *BeaconState) AddHistoricalRoot(root libcommon.Hash) { } func (b *BeaconState) SetInactivityScores(scores []uint64) { - b.inactivityScores = scores + b.inactivityScores.Clear() + for _, v := range scores { + b.inactivityScores.Append(v) + } b.markLeaf(InactivityScoresLeafIndex) } func (b *BeaconState) AddInactivityScore(score uint64) { - b.inactivityScores = append(b.inactivityScores, score) + b.inactivityScores.Append(score) b.markLeaf(InactivityScoresLeafIndex) } func (b *BeaconState) SetValidatorInactivityScore(index int, score uint64) error { - if index >= len(b.inactivityScores) { + if index >= b.inactivityScores.Length() { return ErrInvalidValidatorIndex } b.markLeaf(InactivityScoresLeafIndex) - b.inactivityScores[index] = score + b.inactivityScores.Set(index, score) return nil } diff --git a/cmd/erigon-cl/core/state/raw/ssz.go b/cmd/erigon-cl/core/state/raw/ssz.go index 5a51a6a6cc7..fd923552a2e 100644 --- a/cmd/erigon-cl/core/state/raw/ssz.go +++ b/cmd/erigon-cl/core/state/raw/ssz.go @@ -66,7 +66,7 @@ func (b *BeaconState) EncodeSSZ(buf []byte) ([]byte, error) { return nil, fmt.Errorf("too many validators") } - if len(b.balances) > state_encoding.ValidatorRegistryLimit { + if b.balances.Length() > state_encoding.ValidatorRegistryLimit { return nil, fmt.Errorf("too many balances") } @@ -79,7 +79,7 @@ func (b *BeaconState) EncodeSSZ(buf []byte) ([]byte, error) { return nil, fmt.Errorf("too many participations") } - if len(b.inactivityScores) > state_encoding.ValidatorRegistryLimit { + if b.inactivityScores.Length() > state_encoding.ValidatorRegistryLimit { return nil, fmt.Errorf("too many inactivities scores") } // Start encoding @@ -124,7 +124,7 @@ func (b *BeaconState) EncodeSSZ(buf []byte) ([]byte, error) { // balances offset dst = append(dst, ssz.OffsetSSZ(offset)...) - offset += uint32(len(b.balances)) * 8 + offset += uint32(b.balances.Length()) * 8 for _, mix := range &b.randaoMixes { dst = append(dst, mix[:]...) @@ -172,7 +172,7 @@ func (b *BeaconState) EncodeSSZ(buf []byte) ([]byte, error) { // Inactivity scores offset dst = append(dst, ssz.OffsetSSZ(offset)...) - offset += uint32(len(b.inactivityScores)) * 8 + offset += uint32(b.inactivityScores.Length()) * 8 // Sync commitees if dst, err = b.currentSyncCommittee.EncodeSSZ(dst); err != nil { @@ -211,9 +211,10 @@ func (b *BeaconState) EncodeSSZ(buf []byte) ([]byte, error) { } } // Write balances (offset 4) - for _, balance := range b.balances { - dst = append(dst, ssz.Uint64SSZ(balance)...) - } + b.balances.Range(func(index int, value uint64, length int) bool { + dst = append(dst, ssz.Uint64SSZ(value)...) + return true + }) // Write participations (offset 4 & 5) if b.version == clparams.Phase0Version { @@ -229,9 +230,10 @@ func (b *BeaconState) EncodeSSZ(buf []byte) ([]byte, error) { } if b.version >= clparams.AltairVersion { // write inactivity scores (offset 6) - for _, score := range b.inactivityScores { - dst = append(dst, ssz.Uint64SSZ(score)...) - } + b.inactivityScores.Range(func(index int, value uint64, length int) bool { + dst = append(dst, ssz.Uint64SSZ(value)...) + return true + }) } // write execution header (offset 7) @@ -384,9 +386,11 @@ func (b *BeaconState) DecodeSSZ(buf []byte, version int) error { if b.validators, err = ssz.DecodeStaticList[*cltypes.Validator](buf, validatorsOffset, balancesOffset, 121, state_encoding.ValidatorRegistryLimit, version); err != nil { return err } - if b.balances, err = ssz.DecodeNumbersList(buf, balancesOffset, previousEpochParticipationOffset, state_encoding.ValidatorRegistryLimit); err != nil { + rawBalances, err := ssz.DecodeNumbersList(buf, balancesOffset, previousEpochParticipationOffset, state_encoding.ValidatorRegistryLimit) + if err != nil { return err } + b.SetBalances(rawBalances) if b.version == clparams.Phase0Version { maxAttestations := b.beaconConfig.SlotsPerEpoch * b.beaconConfig.MaxAttestations if b.previousEpochAttestations, err = ssz.DecodeDynamicList[*cltypes.PendingAttestation](buf, previousEpochParticipationOffset, currentEpochParticipationOffset, maxAttestations, version); err != nil { @@ -412,9 +416,11 @@ func (b *BeaconState) DecodeSSZ(buf []byte, version int) error { if executionPayloadOffset != 0 { endOffset = executionPayloadOffset } - if b.inactivityScores, err = ssz.DecodeNumbersList(buf, inactivityScoresOffset, endOffset, state_encoding.ValidatorRegistryLimit); err != nil { + inactivityScores, err := ssz.DecodeNumbersList(buf, inactivityScoresOffset, endOffset, state_encoding.ValidatorRegistryLimit) + if err != nil { return err } + b.SetInactivityScores(inactivityScores) if b.version == clparams.AltairVersion { return b.init() } @@ -445,7 +451,7 @@ func (b *BeaconState) EncodingSizeSSZ() (size int) { size = int(b.baseOffsetSSZ()) + (len(b.historicalRoots) * 32) size += len(b.eth1DataVotes) * 72 size += len(b.validators) * 121 - size += len(b.balances) * 8 + size += b.balances.Length() * 8 if b.version == clparams.Phase0Version { for _, pendingAttestation := range b.previousEpochAttestations { size += pendingAttestation.EncodingSizeSSZ() @@ -458,7 +464,7 @@ func (b *BeaconState) EncodingSizeSSZ() (size int) { size += len(b.currentEpochParticipation) } - size += len(b.inactivityScores) * 8 + size += b.inactivityScores.Length() * 8 size += len(b.historicalSummaries) * 64 return } diff --git a/cmd/erigon-cl/core/state/raw/state.go b/cmd/erigon-cl/core/state/raw/state.go index 7f7f257b359..1c0556cf2b3 100644 --- a/cmd/erigon-cl/core/state/raw/state.go +++ b/cmd/erigon-cl/core/state/raw/state.go @@ -4,6 +4,7 @@ import ( "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon/cl/clparams" "github.com/ledgerwatch/erigon/cl/cltypes" + "github.com/ledgerwatch/erigon/cl/cltypes/solid" ) const ( @@ -27,7 +28,7 @@ type BeaconState struct { eth1DataVotes []*cltypes.Eth1Data eth1DepositIndex uint64 validators []*cltypes.Validator - balances []uint64 + balances solid.Uint64Slice randaoMixes [randoMixesLength]common.Hash slashings [slashingsLength]uint64 previousEpochParticipation cltypes.ParticipationFlagsList @@ -37,7 +38,7 @@ type BeaconState struct { previousJustifiedCheckpoint *cltypes.Checkpoint currentJustifiedCheckpoint *cltypes.Checkpoint finalizedCheckpoint *cltypes.Checkpoint - inactivityScores []uint64 + inactivityScores solid.Uint64Slice currentSyncCommittee *cltypes.SyncCommittee nextSyncCommittee *cltypes.SyncCommittee // Bellatrix @@ -62,6 +63,9 @@ type BeaconState struct { func New(cfg *clparams.BeaconChainConfig) *BeaconState { state := &BeaconState{ beaconConfig: cfg, + //inactivityScores: solid.NewSimpleUint64Slice(int(cfg.ValidatorRegistryLimit)), + inactivityScores: solid.NewUint64Slice(int(cfg.ValidatorRegistryLimit)), + balances: solid.NewUint64Slice(int(cfg.ValidatorRegistryLimit)), } state.init() return state @@ -72,5 +76,4 @@ func (b *BeaconState) init() error { b.touchedLeaves = make(map[StateLeafIndex]bool) } return nil - } diff --git a/cmd/erigon-cl/core/state/raw/test_util.go b/cmd/erigon-cl/core/state/raw/test_util.go index bc0d3bb185c..78b251cace6 100644 --- a/cmd/erigon-cl/core/state/raw/test_util.go +++ b/cmd/erigon-cl/core/state/raw/test_util.go @@ -3,9 +3,11 @@ package raw import ( "github.com/ledgerwatch/erigon/cl/clparams" "github.com/ledgerwatch/erigon/cl/cltypes" + "github.com/ledgerwatch/erigon/cl/cltypes/solid" ) func GetEmptyBeaconState() *BeaconState { + cfg := &clparams.MainnetBeaconConfig b := &BeaconState{ fork: &cltypes.Fork{}, latestBlockHeader: &cltypes.BeaconBlockHeader{}, @@ -21,7 +23,9 @@ func GetEmptyBeaconState() *BeaconState { finalizedCheckpoint: &cltypes.Checkpoint{}, latestExecutionPayloadHeader: cltypes.NewEth1Header(clparams.BellatrixVersion), version: clparams.BellatrixVersion, - beaconConfig: &clparams.MainnetBeaconConfig, + beaconConfig: cfg, + inactivityScores: solid.NewUint64Slice(int(cfg.ValidatorRegistryLimit)), + balances: solid.NewUint64Slice(int(cfg.ValidatorRegistryLimit)), } b.init() return b diff --git a/cmd/erigon-cl/core/state/shuffling/shuffling.go b/cmd/erigon-cl/core/state/shuffling/shuffling.go index 5fc375bf6fb..9c39fda4c89 100644 --- a/cmd/erigon-cl/core/state/shuffling/shuffling.go +++ b/cmd/erigon-cl/core/state/shuffling/shuffling.go @@ -33,7 +33,7 @@ func ComputeProposerIndex(b *raw.BeaconState, indices []uint64, seed [32]byte) ( if err != nil { return 0, err } - if validator.EffectiveBalance*maxRandomByte >= b.BeaconConfig().MaxEffectiveBalance*randomByte { + if validator.EffectiveBalance()*maxRandomByte >= b.BeaconConfig().MaxEffectiveBalance*randomByte { return candidateIndex, nil } i += 1 diff --git a/cmd/erigon-cl/core/state/util.go b/cmd/erigon-cl/core/state/util.go index 6e41a9a2069..f88a1df61c6 100644 --- a/cmd/erigon-cl/core/state/util.go +++ b/cmd/erigon-cl/core/state/util.go @@ -13,6 +13,7 @@ func copyLRU[K comparable, V any](dst *lru.Cache[K, V], src *lru.Cache[K, V]) *l if dst == nil { dst = new(lru.Cache[K, V]) } + dst.Purge() for _, key := range src.Keys() { val, has := src.Get(key) if !has { @@ -39,27 +40,27 @@ func ValidatorFromDeposit(conf *clparams.BeaconChainConfig, deposit *cltypes.Dep amount := deposit.Data.Amount effectiveBalance := utils.Min64(amount-amount%conf.EffectiveBalanceIncrement, conf.MaxEffectiveBalance) - return &cltypes.Validator{ - PublicKey: deposit.Data.PubKey, - WithdrawalCredentials: deposit.Data.WithdrawalCredentials, - ActivationEligibilityEpoch: conf.FarFutureEpoch, - ActivationEpoch: conf.FarFutureEpoch, - ExitEpoch: conf.FarFutureEpoch, - WithdrawableEpoch: conf.FarFutureEpoch, - EffectiveBalance: effectiveBalance, - } + validator := &cltypes.Validator{} + validator.SetPublicKey(deposit.Data.PubKey) + validator.SetWithdrawalCredentials(deposit.Data.WithdrawalCredentials) + validator.SetActivationEligibilityEpoch(conf.FarFutureEpoch) + validator.SetActivationEpoch(conf.FarFutureEpoch) + validator.SetExitEpoch(conf.FarFutureEpoch) + validator.SetWithdrawableEpoch(conf.FarFutureEpoch) + validator.SetEffectiveBalance(effectiveBalance) + return validator } // Check whether a validator is fully withdrawable at the given epoch. func isFullyWithdrawableValidator(conf *clparams.BeaconChainConfig, validator *cltypes.Validator, balance uint64, epoch uint64) bool { - return validator.WithdrawalCredentials[0] == conf.ETH1AddressWithdrawalPrefixByte && - validator.WithdrawableEpoch <= epoch && balance > 0 + return validator.WithdrawalCredentials()[0] == conf.ETH1AddressWithdrawalPrefixByte && + validator.WithdrawableEpoch() <= epoch && balance > 0 } // Check whether a validator is partially withdrawable. func isPartiallyWithdrawableValidator(conf *clparams.BeaconChainConfig, validator *cltypes.Validator, balance uint64) bool { - return validator.WithdrawalCredentials[0] == conf.ETH1AddressWithdrawalPrefixByte && - validator.EffectiveBalance == conf.MaxEffectiveBalance && balance > conf.MaxEffectiveBalance + return validator.WithdrawalCredentials()[0] == conf.ETH1AddressWithdrawalPrefixByte && + validator.EffectiveBalance() == conf.MaxEffectiveBalance && balance > conf.MaxEffectiveBalance } func ComputeActivationExitEpoch(config *clparams.BeaconChainConfig, epoch uint64) uint64 { diff --git a/cmd/erigon-cl/core/transition/finalization_and_justification.go b/cmd/erigon-cl/core/transition/finalization_and_justification.go index f6a4fcedcc9..7b7153c173e 100644 --- a/cmd/erigon-cl/core/transition/finalization_and_justification.go +++ b/cmd/erigon-cl/core/transition/finalization_and_justification.go @@ -71,33 +71,35 @@ func ProcessJustificationBitsAndFinality(s *state.BeaconState) error { } var previousTargetBalance, currentTargetBalance uint64 if s.Version() == clparams.Phase0Version { - for _, validator := range s.Validators() { - if validator.Slashed { - continue + s.ForEachValidator(func(validator *cltypes.Validator, idx, total int) bool { + if validator.Slashed() { + return true } if validator.IsCurrentMatchingTargetAttester { - currentTargetBalance += validator.EffectiveBalance + currentTargetBalance += validator.EffectiveBalance() } if validator.IsPreviousMatchingTargetAttester { - previousTargetBalance += validator.EffectiveBalance + previousTargetBalance += validator.EffectiveBalance() } - } + return true + }) } else { // Use bitlists to determine finality. previousParticipation, currentParticipation := s.EpochParticipation(false), s.EpochParticipation(true) - for i, validator := range s.Validators() { - if validator.Slashed { - continue + s.ForEachValidator(func(validator *cltypes.Validator, i, total int) bool { + if validator.Slashed() { + return true } if validator.Active(previousEpoch) && previousParticipation[i].HasFlag(int(beaconConfig.TimelyTargetFlagIndex)) { - previousTargetBalance += validator.EffectiveBalance + previousTargetBalance += validator.EffectiveBalance() } if validator.Active(currentEpoch) && currentParticipation[i].HasFlag(int(beaconConfig.TimelyTargetFlagIndex)) { - currentTargetBalance += validator.EffectiveBalance + currentTargetBalance += validator.EffectiveBalance() } - } + return true + }) } return weighJustificationAndFinalization(s, previousTargetBalance, currentTargetBalance) diff --git a/cmd/erigon-cl/core/transition/operations.go b/cmd/erigon-cl/core/transition/operations.go index 71994641ed2..370e5e79415 100644 --- a/cmd/erigon-cl/core/transition/operations.go +++ b/cmd/erigon-cl/core/transition/operations.go @@ -56,12 +56,13 @@ func ProcessProposerSlashing(s *state.BeaconState, propSlashing *cltypes.Propose if err != nil { return fmt.Errorf("unable to compute signing root: %v", err) } - valid, err := bls.Verify(signedHeader.Signature[:], signingRoot[:], proposer.PublicKey[:]) + pk := proposer.PublicKey() + valid, err := bls.Verify(signedHeader.Signature[:], signingRoot[:], pk[:]) if err != nil { return fmt.Errorf("unable to verify signature: %v", err) } if !valid { - return fmt.Errorf("invalid signature: signature %v, root %v, pubkey %v", signedHeader.Signature[:], signingRoot[:], proposer.PublicKey[:]) + return fmt.Errorf("invalid signature: signature %v, root %v, pubkey %v", signedHeader.Signature[:], signingRoot[:], pk) } } @@ -187,13 +188,13 @@ func ProcessVoluntaryExit(s *state.BeaconState, signedVoluntaryExit *cltypes.Sig if !validator.Active(currentEpoch) { return errors.New("ProcessVoluntaryExit: validator is not active") } - if validator.ExitEpoch != s.BeaconConfig().FarFutureEpoch { + if validator.ExitEpoch() != s.BeaconConfig().FarFutureEpoch { return errors.New("ProcessVoluntaryExit: another exit for the same validator is already getting processed") } if currentEpoch < voluntaryExit.Epoch { return errors.New("ProcessVoluntaryExit: exit is happening in the future") } - if currentEpoch < validator.ActivationEpoch+s.BeaconConfig().ShardCommitteePeriod { + if currentEpoch < validator.ActivationEpoch()+s.BeaconConfig().ShardCommitteePeriod { return errors.New("ProcessVoluntaryExit: exit is happening too fast") } @@ -207,7 +208,8 @@ func ProcessVoluntaryExit(s *state.BeaconState, signedVoluntaryExit *cltypes.Sig if err != nil { return err } - valid, err := bls.Verify(signedVoluntaryExit.Signature[:], signingRoot[:], validator.PublicKey[:]) + pk := validator.PublicKey() + valid, err := bls.Verify(signedVoluntaryExit.Signature[:], signingRoot[:], pk[:]) if err != nil { return err } @@ -225,7 +227,7 @@ func ProcessWithdrawals(s *state.BeaconState, withdrawals types.Withdrawals, ful // Get the list of withdrawals, the expected withdrawals (if performing full validation), // and the beacon configuration. beaconConfig := s.BeaconConfig() - numValidators := uint64(len(s.Validators())) + numValidators := uint64(s.ValidatorLength()) // Check if full validation is required and verify expected withdrawals. if fullValidation { diff --git a/cmd/erigon-cl/core/transition/process_attestations.go b/cmd/erigon-cl/core/transition/process_attestations.go index 1605e3146d5..aad7f144854 100644 --- a/cmd/erigon-cl/core/transition/process_attestations.go +++ b/cmd/erigon-cl/core/transition/process_attestations.go @@ -54,9 +54,13 @@ func processAttestationPostAltair(s *state.BeaconState, attestation *cltypes.Att isCurrentEpoch := data.Target.Epoch == currentEpoch - validators := s.Validators() for _, attesterIndex := range attestingIndicies { - baseReward := (validators[attesterIndex].EffectiveBalance / beaconConfig.EffectiveBalanceIncrement) * baseRewardPerIncrement + val, err := s.ValidatorEffectiveBalance(int(attesterIndex)) + if err != nil { + return nil, err + } + + baseReward := (val / beaconConfig.EffectiveBalanceIncrement) * baseRewardPerIncrement for flagIndex, weight := range beaconConfig.ParticipationWeights() { flagParticipation := s.EpochParticipationForValidatorIndex(isCurrentEpoch, int(attesterIndex)) if !slices.Contains(participationFlagsIndicies, uint8(flagIndex)) || flagParticipation.HasFlag(flagIndex) { diff --git a/cmd/erigon-cl/core/transition/process_bls_to_execution_change.go b/cmd/erigon-cl/core/transition/process_bls_to_execution_change.go index 9b0e0686f59..66e811e0b87 100644 --- a/cmd/erigon-cl/core/transition/process_bls_to_execution_change.go +++ b/cmd/erigon-cl/core/transition/process_bls_to_execution_change.go @@ -22,15 +22,16 @@ func ProcessBlsToExecutionChange(state *state.BeaconState, signedChange *cltypes } // Perform full validation if requested. + wc := validator.WithdrawalCredentials() if fullValidation { // Check the validator's withdrawal credentials prefix. - if validator.WithdrawalCredentials[0] != beaconConfig.BLSWithdrawalPrefixByte { + if wc[0] != beaconConfig.BLSWithdrawalPrefixByte { return fmt.Errorf("invalid withdrawal credentials prefix") } // Check the validator's withdrawal credentials against the provided message. hashedFrom := utils.Keccak256(change.From[:]) - if !bytes.Equal(hashedFrom[1:], validator.WithdrawalCredentials[1:]) { + if !bytes.Equal(hashedFrom[1:], wc[1:]) { return fmt.Errorf("invalid withdrawal credentials") } @@ -51,7 +52,7 @@ func ProcessBlsToExecutionChange(state *state.BeaconState, signedChange *cltypes return fmt.Errorf("invalid signature") } } - credentials := validator.WithdrawalCredentials + credentials := wc // Reset the validator's withdrawal credentials. credentials[0] = beaconConfig.ETH1AddressWithdrawalPrefixByte copy(credentials[1:], make([]byte, 11)) diff --git a/cmd/erigon-cl/core/transition/process_effective_balance_update.go b/cmd/erigon-cl/core/transition/process_effective_balance_update.go index a6c9d58508f..e98cc39c94d 100644 --- a/cmd/erigon-cl/core/transition/process_effective_balance_update.go +++ b/cmd/erigon-cl/core/transition/process_effective_balance_update.go @@ -1,6 +1,7 @@ package transition import ( + "github.com/ledgerwatch/erigon/cl/cltypes" "github.com/ledgerwatch/erigon/cl/utils" "github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state" ) @@ -13,17 +14,23 @@ func ProcessEffectiveBalanceUpdates(state *state.BeaconState) error { downwardThreshold := histeresisIncrement * beaconConfig.HysteresisDownwardMultiplier upwardThreshold := histeresisIncrement * beaconConfig.HysteresisUpwardMultiplier // Iterate over validator set and compute the diff of each validator. - for index, validator := range state.Validators() { - balance, err := state.ValidatorBalance(index) + var err error + var balance uint64 + state.ForEachValidator(func(validator *cltypes.Validator, index, total int) bool { + balance, err = state.ValidatorBalance(index) if err != nil { - return err + return false } - if balance+downwardThreshold < validator.EffectiveBalance || - validator.EffectiveBalance+upwardThreshold < balance { + eb := validator.EffectiveBalance() + if balance+downwardThreshold < eb || eb+upwardThreshold < balance { // Set new effective balance effectiveBalance := utils.Min64(balance-(balance%beaconConfig.EffectiveBalanceIncrement), beaconConfig.MaxEffectiveBalance) state.SetEffectiveBalanceForValidatorAtIndex(index, effectiveBalance) } + return true + }) + if err != nil { + return err } return nil } diff --git a/cmd/erigon-cl/core/transition/process_epoch.go b/cmd/erigon-cl/core/transition/process_epoch.go index 77fd00e4aa9..8d0e137681b 100644 --- a/cmd/erigon-cl/core/transition/process_epoch.go +++ b/cmd/erigon-cl/core/transition/process_epoch.go @@ -2,6 +2,7 @@ package transition import ( "github.com/ledgerwatch/erigon/cl/clparams" + "github.com/ledgerwatch/erigon/cl/cltypes" "github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state" ) @@ -52,7 +53,7 @@ func ProcessParticipationRecordUpdates(state *state.BeaconState) error { state.SetPreviousEpochAttestations(state.CurrentEpochAttestations()) state.ResetCurrentEpochAttestations() // Also mark all current attesters as previous - for _, validator := range state.Validators() { + state.ForEachValidator(func(validator *cltypes.Validator, idx, total int) bool { // Previous sources/target/head validator.IsPreviousMatchingSourceAttester = validator.IsCurrentMatchingSourceAttester validator.IsPreviousMatchingTargetAttester = validator.IsCurrentMatchingTargetAttester @@ -63,6 +64,7 @@ func ProcessParticipationRecordUpdates(state *state.BeaconState) error { validator.IsCurrentMatchingSourceAttester = false validator.IsCurrentMatchingTargetAttester = false validator.IsCurrentMatchingHeadAttester = false - } + return true + }) return nil } diff --git a/cmd/erigon-cl/core/transition/process_registry_updates.go b/cmd/erigon-cl/core/transition/process_registry_updates.go index 67524f437bd..c8138293eff 100644 --- a/cmd/erigon-cl/core/transition/process_registry_updates.go +++ b/cmd/erigon-cl/core/transition/process_registry_updates.go @@ -4,6 +4,7 @@ import ( "sort" "github.com/ledgerwatch/erigon/cl/clparams" + "github.com/ledgerwatch/erigon/cl/cltypes" "github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state" ) @@ -18,27 +19,33 @@ func ProcessRegistryUpdates(s *state.BeaconState) error { currentEpoch := state.Epoch(s.BeaconState) // start also initializing the activation queue. activationQueue := make([]uint64, 0) - validators := s.Validators() // Process activation eligibility and ejections. - for validatorIndex, validator := range validators { + var err error + s.ForEachValidator(func(validator *cltypes.Validator, validatorIndex, total int) bool { if state.IsValidatorEligibleForActivationQueue(s.BeaconState, validator) { s.SetActivationEligibilityEpochForValidatorAtIndex(validatorIndex, currentEpoch+1) } - if validator.Active(currentEpoch) && validator.EffectiveBalance <= beaconConfig.EjectionBalance { - if err := s.InitiateValidatorExit(uint64(validatorIndex)); err != nil { - return err + if validator.Active(currentEpoch) && validator.EffectiveBalance() <= beaconConfig.EjectionBalance { + if err = s.InitiateValidatorExit(uint64(validatorIndex)); err != nil { + return false } } // Insert in the activation queue in case. if state.IsValidatorEligibleForActivation(s.BeaconState, validator) { activationQueue = append(activationQueue, uint64(validatorIndex)) } + return true + }) + if err != nil { + return err } // order the queue accordingly. sort.Slice(activationQueue, func(i, j int) bool { // Order by the sequence of activation_eligibility_epoch setting and then index. - if validators[activationQueue[i]].ActivationEligibilityEpoch != validators[activationQueue[j]].ActivationEligibilityEpoch { - return validators[activationQueue[i]].ActivationEligibilityEpoch < validators[activationQueue[j]].ActivationEligibilityEpoch + validatori, _ := s.ValidatorForValidatorIndex(int(activationQueue[i])) + validatorj, _ := s.ValidatorForValidatorIndex(int(activationQueue[j])) + if validatori.ActivationEligibilityEpoch() != validatorj.ActivationEligibilityEpoch() { + return validatori.ActivationEligibilityEpoch() < validatorj.ActivationEligibilityEpoch() } return activationQueue[i] < activationQueue[j] }) diff --git a/cmd/erigon-cl/core/transition/process_rewards_and_penalties.go b/cmd/erigon-cl/core/transition/process_rewards_and_penalties.go index 412992bf579..17ee66463ba 100644 --- a/cmd/erigon-cl/core/transition/process_rewards_and_penalties.go +++ b/cmd/erigon-cl/core/transition/process_rewards_and_penalties.go @@ -2,6 +2,7 @@ package transition import ( "github.com/ledgerwatch/erigon/cl/clparams" + "github.com/ledgerwatch/erigon/cl/cltypes" "github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state" ) @@ -12,19 +13,19 @@ func processRewardsAndPenaltiesPostAltair(s *state.BeaconState) (err error) { // Initialize variables totalActiveBalance := s.GetTotalActiveBalance() previousEpoch := state.PreviousEpoch(s.BeaconState) - validators := s.Validators() // Inactivity penalties denominator. inactivityPenaltyDenominator := beaconConfig.InactivityScoreBias * beaconConfig.GetPenaltyQuotient(s.Version()) // Make buffer for flag indexes total balances. flagsTotalBalances := make([]uint64, len(weights)) // Compute all total balances for each enable unslashed validator indicies with all flags on. - for validatorIndex, validator := range s.Validators() { + s.ForEachValidator(func(validator *cltypes.Validator, validatorIndex, total int) bool { for i := range weights { if state.IsUnslashedParticipatingIndex(s.BeaconState, previousEpoch, uint64(validatorIndex), i) { - flagsTotalBalances[i] += validator.EffectiveBalance + flagsTotalBalances[i] += validator.EffectiveBalance() } } - } + return true + }) // precomputed multiplier for reward. rewardMultipliers := make([]uint64, len(weights)) for i := range weights { @@ -58,7 +59,11 @@ func processRewardsAndPenaltiesPostAltair(s *state.BeaconState) (err error) { return err } // Process inactivity penalties. - state.DecreaseBalance(s.BeaconState, index, (validators[index].EffectiveBalance*inactivityScore)/inactivityPenaltyDenominator) + effectiveBalance, err := s.ValidatorEffectiveBalance(int(index)) + if err != nil { + return err + } + state.DecreaseBalance(s.BeaconState, index, (effectiveBalance*inactivityScore)/inactivityPenaltyDenominator) } } return @@ -73,24 +78,24 @@ func processRewardsAndPenaltiesPhase0(s *state.BeaconState) (err error) { eligibleValidators := state.EligibleValidatorsIndicies(s.BeaconState) // Initialize variables rewardDenominator := s.GetTotalActiveBalance() / beaconConfig.EffectiveBalanceIncrement - validators := s.Validators() // Make buffer for flag indexes totTargetal balances. var unslashedMatchingSourceBalanceIncrements, unslashedMatchingTargetBalanceIncrements, unslashedMatchingHeadBalanceIncrements uint64 // Compute all total balances for each enable unslashed validator indicies with all flags on. - for _, validator := range s.Validators() { - if validator.Slashed { - continue + s.ForEachValidator(func(validator *cltypes.Validator, idx, total int) bool { + if validator.Slashed() { + return true } if validator.IsPreviousMatchingSourceAttester { - unslashedMatchingSourceBalanceIncrements += validator.EffectiveBalance + unslashedMatchingSourceBalanceIncrements += validator.EffectiveBalance() } if validator.IsPreviousMatchingTargetAttester { - unslashedMatchingTargetBalanceIncrements += validator.EffectiveBalance + unslashedMatchingTargetBalanceIncrements += validator.EffectiveBalance() } if validator.IsPreviousMatchingHeadAttester { - unslashedMatchingHeadBalanceIncrements += validator.EffectiveBalance + unslashedMatchingHeadBalanceIncrements += validator.EffectiveBalance() } - } + return true + }) // Then compute their total increment. unslashedMatchingSourceBalanceIncrements /= beaconConfig.EffectiveBalanceIncrement unslashedMatchingTargetBalanceIncrements /= beaconConfig.EffectiveBalanceIncrement @@ -101,27 +106,31 @@ func processRewardsAndPenaltiesPhase0(s *state.BeaconState) (err error) { if err != nil { return err } + currentValidator, err := s.ValidatorForValidatorIndex(int(index)) + if err != nil { + return err + } // we can use a multiplier to account for all attesting - attested, missed := validators[index].DutiesAttested() + attested, missed := currentValidator.DutiesAttested() // If we attested then we reward the validator. if state.InactivityLeaking(s.BeaconState) { if err := state.IncreaseBalance(s.BeaconState, index, baseReward*attested); err != nil { return err } } else { - if !validators[index].Slashed && validators[index].IsPreviousMatchingSourceAttester { + if !currentValidator.Slashed() && currentValidator.IsPreviousMatchingSourceAttester { rewardNumerator := baseReward * unslashedMatchingSourceBalanceIncrements if err := state.IncreaseBalance(s.BeaconState, index, rewardNumerator/rewardDenominator); err != nil { return err } } - if !validators[index].Slashed && validators[index].IsPreviousMatchingTargetAttester { + if !currentValidator.Slashed() && currentValidator.IsPreviousMatchingTargetAttester { rewardNumerator := baseReward * unslashedMatchingTargetBalanceIncrements if err := state.IncreaseBalance(s.BeaconState, index, rewardNumerator/rewardDenominator); err != nil { return err } } - if !validators[index].Slashed && validators[index].IsPreviousMatchingHeadAttester { + if !currentValidator.Slashed() && currentValidator.IsPreviousMatchingHeadAttester { rewardNumerator := baseReward * unslashedMatchingHeadBalanceIncrements if err := state.IncreaseBalance(s.BeaconState, index, rewardNumerator/rewardDenominator); err != nil { return err @@ -135,9 +144,9 @@ func processRewardsAndPenaltiesPhase0(s *state.BeaconState) (err error) { if state.DecreaseBalance(s.BeaconState, index, beaconConfig.BaseRewardsPerEpoch*baseReward-proposerReward); err != nil { return err } - if validators[index].Slashed || !validators[index].IsPreviousMatchingTargetAttester { + if currentValidator.Slashed() || !currentValidator.IsPreviousMatchingTargetAttester { // Increase penalities linearly if network is leaking. - if state.DecreaseBalance(s.BeaconState, index, validators[index].EffectiveBalance*state.FinalityDelay(s.BeaconState)/beaconConfig.InactivityPenaltyQuotient); err != nil { + if state.DecreaseBalance(s.BeaconState, index, currentValidator.EffectiveBalance()*state.FinalityDelay(s.BeaconState)/beaconConfig.InactivityPenaltyQuotient); err != nil { return err } } @@ -150,24 +159,30 @@ func processRewardsAndPenaltiesPhase0(s *state.BeaconState) (err error) { } // Lastly process late attestations - for index, validator := range validators { - if validator.Slashed || !validator.IsPreviousMatchingSourceAttester { - continue + + s.ForEachValidator(func(validator *cltypes.Validator, index, total int) bool { + if validator.Slashed() || !validator.IsPreviousMatchingSourceAttester { + return true } - attestation := validators[index].MinPreviousInclusionDelayAttestation - baseReward, err := s.BaseReward(uint64(index)) + attestation := validator.MinPreviousInclusionDelayAttestation + var baseReward uint64 + baseReward, err = s.BaseReward(uint64(index)) if err != nil { - return err + return false } // Compute proposer reward. proposerReward := (baseReward / beaconConfig.ProposerRewardQuotient) - if err := state.IncreaseBalance(s.BeaconState, attestation.ProposerIndex, proposerReward); err != nil { - return err + if err = state.IncreaseBalance(s.BeaconState, attestation.ProposerIndex, proposerReward); err != nil { + return false } maxAttesterReward := baseReward - proposerReward - if err := state.IncreaseBalance(s.BeaconState, uint64(index), maxAttesterReward/attestation.InclusionDelay); err != nil { - return err + if err = state.IncreaseBalance(s.BeaconState, uint64(index), maxAttesterReward/attestation.InclusionDelay); err != nil { + return false } + return true + }) + if err != nil { + return err } return } diff --git a/cmd/erigon-cl/core/transition/process_slashings.go b/cmd/erigon-cl/core/transition/process_slashings.go index 27271e4a0ff..03d88eb5823 100644 --- a/cmd/erigon-cl/core/transition/process_slashings.go +++ b/cmd/erigon-cl/core/transition/process_slashings.go @@ -2,6 +2,7 @@ package transition import ( "github.com/ledgerwatch/erigon/cl/clparams" + "github.com/ledgerwatch/erigon/cl/cltypes" "github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state" ) @@ -19,20 +20,25 @@ func processSlashings(s *state.BeaconState, slashingMultiplier uint64) error { } beaconConfig := s.BeaconConfig() // Apply penalties to validators who have been slashed and reached the withdrawable epoch - for i, validator := range s.Validators() { - if !validator.Slashed || epoch+beaconConfig.EpochsPerSlashingsVector/2 != validator.WithdrawableEpoch { - continue + var err error + s.ForEachValidator(func(validator *cltypes.Validator, i, total int) bool { + if !validator.Slashed() || epoch+beaconConfig.EpochsPerSlashingsVector/2 != validator.WithdrawableEpoch() { + return true } // Get the effective balance increment increment := beaconConfig.EffectiveBalanceIncrement // Calculate the penalty numerator by multiplying the validator's effective balance by the total slashing amount - penaltyNumerator := validator.EffectiveBalance / increment * slashing + penaltyNumerator := validator.EffectiveBalance() / increment * slashing // Calculate the penalty by dividing the penalty numerator by the total balance and multiplying by the increment penalty := penaltyNumerator / totalBalance * increment // Decrease the validator's balance by the calculated penalty - if err := state.DecreaseBalance(s.BeaconState, uint64(i), penalty); err != nil { - return err + if err = state.DecreaseBalance(s.BeaconState, uint64(i), penalty); err != nil { + return false } + return true + }) + if err != nil { + return err } return nil } diff --git a/cmd/erigon-cl/core/transition/process_slots.go b/cmd/erigon-cl/core/transition/process_slots.go index 20b90293989..e18c2d90d19 100644 --- a/cmd/erigon-cl/core/transition/process_slots.go +++ b/cmd/erigon-cl/core/transition/process_slots.go @@ -145,7 +145,8 @@ func verifyBlockSignature(s *state.BeaconState, block *cltypes.SignedBeaconBlock if err != nil { return false, err } - return bls.Verify(block.Signature[:], sigRoot[:], proposer.PublicKey[:]) + pk := proposer.PublicKey() + return bls.Verify(block.Signature[:], sigRoot[:], pk[:]) } // ProcessHistoricalRootsUpdate updates the historical root data structure by computing a new historical root batch when it is time to do so. diff --git a/cmd/erigon-cl/core/transition/processing.go b/cmd/erigon-cl/core/transition/processing.go index bbe72ab6b29..a5afa127a78 100644 --- a/cmd/erigon-cl/core/transition/processing.go +++ b/cmd/erigon-cl/core/transition/processing.go @@ -58,7 +58,7 @@ func ProcessBlockHeader(state *state.BeaconState, block *cltypes.BeaconBlock, fu if err != nil { return err } - if proposer.Slashed { + if proposer.Slashed() { return fmt.Errorf("proposer: %d is slashed", block.ProposerIndex) } return nil @@ -79,12 +79,13 @@ func ProcessRandao(s *state.BeaconState, randao [96]byte, proposerIndex uint64, if err != nil { return fmt.Errorf("ProcessRandao: unable to compute signing root: %v", err) } - valid, err := bls.Verify(randao[:], signingRoot[:], proposer.PublicKey[:]) + pk := proposer.PublicKey() + valid, err := bls.Verify(randao[:], signingRoot[:], pk[:]) if err != nil { - return fmt.Errorf("ProcessRandao: unable to verify public key: %x, with signing root: %x, and signature: %x, %v", proposer.PublicKey[:], signingRoot[:], randao[:], err) + return fmt.Errorf("ProcessRandao: unable to verify public key: %x, with signing root: %x, and signature: %x, %v", pk[:], signingRoot[:], randao[:], err) } if !valid { - return fmt.Errorf("ProcessRandao: invalid signature: public key: %x, signing root: %x, signature: %x", proposer.PublicKey[:], signingRoot[:], randao[:]) + return fmt.Errorf("ProcessRandao: invalid signature: public key: %x, signing root: %x, signature: %x", pk[:], signingRoot[:], randao[:]) } } diff --git a/cmd/erigon-cl/forkchoice/checkpoint_state.go b/cmd/erigon-cl/forkchoice/checkpoint_state.go index 1c138c36856..8df981a2f27 100644 --- a/cmd/erigon-cl/forkchoice/checkpoint_state.go +++ b/cmd/erigon-cl/forkchoice/checkpoint_state.go @@ -57,11 +57,11 @@ func newCheckpointState(beaconConfig *clparams.BeaconChainConfig, validatorSet [ validators := make([]*checkpointValidator, len(validatorSet)) for i := range validatorSet { validators[i] = &checkpointValidator{ - publicKey: validatorSet[i].PublicKey, - activationEpoch: validatorSet[i].ActivationEpoch, - exitEpoch: validatorSet[i].ExitEpoch, - balance: validatorSet[i].EffectiveBalance, - slashed: validatorSet[i].Slashed, + publicKey: validatorSet[i].PublicKey(), + activationEpoch: validatorSet[i].ActivationEpoch(), + exitEpoch: validatorSet[i].ExitEpoch(), + balance: validatorSet[i].EffectiveBalance(), + slashed: validatorSet[i].Slashed(), } } return &checkpointState{ diff --git a/cmd/erigon-cl/forkchoice/utils.go b/cmd/erigon-cl/forkchoice/utils.go index ddc9a60224d..682e2680863 100644 --- a/cmd/erigon-cl/forkchoice/utils.go +++ b/cmd/erigon-cl/forkchoice/utils.go @@ -89,7 +89,13 @@ func (f *ForkChoiceStore) getCheckpointState(checkpoint cltypes.Checkpoint) (*ch } } mixes := baseState.RandaoMixes() - checkpointState := newCheckpointState(f.forkGraph.Config(), baseState.Validators(), + // TODO: make this copy smarter when validators is a smarter struct + validators := make([]*cltypes.Validator, baseState.ValidatorLength()) + baseState.ForEachValidator(func(v *cltypes.Validator, idx, total int) bool { + validators[idx] = v + return true + }) + checkpointState := newCheckpointState(f.forkGraph.Config(), validators, mixes[:], baseState.GenesisValidatorsRoot(), baseState.Fork(), baseState.GetTotalActiveBalance(), state.Epoch(baseState.BeaconState)) // Cache in memory what we are left with. f.checkpointStates.Add(checkpoint, checkpointState) From 76c7111094f30083037950bcacaf575445ab4985 Mon Sep 17 00:00:00 2001 From: a Date: Sun, 7 May 2023 01:31:32 -0500 Subject: [PATCH 02/34] fix build --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index b5dc35cd42c..66024f30ab5 100644 --- a/go.mod +++ b/go.mod @@ -68,7 +68,7 @@ require ( github.com/protolambda/eth2-shuffle v1.1.0 github.com/protolambda/ztyp v0.2.2 github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 - github.com/prysmaticlabs/gohashtree v0.0.3-alpha + github.com/prysmaticlabs/gohashtree v0.0.3-alpha.0.20230502123415-aafd8b3ca202 github.com/quasilyte/go-ruleguard/dsl v0.3.22 github.com/rs/cors v1.9.0 github.com/shirou/gopsutil/v3 v3.23.4 diff --git a/go.sum b/go.sum index 9d2d9ce802e..cd3ed6aeff8 100644 --- a/go.sum +++ b/go.sum @@ -681,6 +681,8 @@ github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 h1:0tVE4 github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7/go.mod h1:wmuf/mdK4VMD+jA9ThwcUKjg3a2XWM9cVfFYjDyY4j4= github.com/prysmaticlabs/gohashtree v0.0.3-alpha h1:1EVinCWdb3Lorq7xn8DYQHf48nCcdAM3Vb18KsFlRWY= github.com/prysmaticlabs/gohashtree v0.0.3-alpha/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk= +github.com/prysmaticlabs/gohashtree v0.0.3-alpha.0.20230502123415-aafd8b3ca202 h1:ZsFouPKy81vvQo/Zup5gASVdOm6aiuwUhp7GxvQmjIA= +github.com/prysmaticlabs/gohashtree v0.0.3-alpha.0.20230502123415-aafd8b3ca202/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk= github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE= github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= From 833b14d6a37fa568addc51e73e7c395e60553aef Mon Sep 17 00:00:00 2001 From: a Date: Sun, 7 May 2023 01:43:58 -0500 Subject: [PATCH 03/34] opatch --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 66024f30ab5..ade1be8ec10 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( require ( gfx.cafe/util/go/generic v0.0.0-20230502013805-237fcc25d586 github.com/99designs/gqlgen v0.17.30 - github.com/Giulio2002/bls v0.0.0-20230428210858-67fd06bbe237 + github.com/Giulio2002/bls v0.0.0-20230506124236-f7b02834db57 github.com/RoaringBitmap/roaring v1.2.3 github.com/VictoriaMetrics/fastcache v1.12.1 github.com/VictoriaMetrics/metrics v1.23.1 diff --git a/go.sum b/go.sum index cd3ed6aeff8..b304ba1e121 100644 --- a/go.sum +++ b/go.sum @@ -20,6 +20,8 @@ github.com/99designs/gqlgen v0.17.30/go.mod h1:i4rEatMrzzu6RXaHydq1nmEPZkb3bKQsn github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Giulio2002/bls v0.0.0-20230428210858-67fd06bbe237 h1:YSnR8buOFFDoIdGkkZ588jlaUXRHpBTrlauANv9wdD0= github.com/Giulio2002/bls v0.0.0-20230428210858-67fd06bbe237/go.mod h1:o6qWofeW8A1XImbo3eHbC/wXnw/dasu0YuHEtdrjYzw= +github.com/Giulio2002/bls v0.0.0-20230506124236-f7b02834db57 h1:DVxkPKa/TsvE/iouZmaEHQmo7qwbVIcAHhFn0tAPz3s= +github.com/Giulio2002/bls v0.0.0-20230506124236-f7b02834db57/go.mod h1:o6qWofeW8A1XImbo3eHbC/wXnw/dasu0YuHEtdrjYzw= github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w= github.com/RoaringBitmap/roaring v0.4.17/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI= github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo= From abbd5e069aa765fad2118b35819fa8f52d11ad07 Mon Sep 17 00:00:00 2001 From: a Date: Sun, 7 May 2023 06:04:11 -0500 Subject: [PATCH 04/34] wip fix test broken another patch more fix --- cl/cltypes/solid/bitlist.go | 80 +++++++++++++++++++ cl/cltypes/solid/interfaces.go | 14 ++++ cl/cltypes/solid/uint64slice_byte_test.go | 4 +- cl/cltypes/solid/validator.go | 23 ++++++ cl/cltypes/validator_test.go | 47 +++++------ cmd/erigon-cl/core/state/accessors.go | 7 +- cmd/erigon-cl/core/state/raw/copy.go | 4 +- cmd/erigon-cl/core/state/raw/getters.go | 7 +- cmd/erigon-cl/core/state/raw/hashing.go | 4 +- cmd/erigon-cl/core/state/raw/setters.go | 24 ++++-- cmd/erigon-cl/core/state/raw/ssz.go | 19 ++--- cmd/erigon-cl/core/state/raw/state.go | 11 ++- .../finalization_and_justification.go | 4 +- 13 files changed, 189 insertions(+), 59 deletions(-) create mode 100644 cl/cltypes/solid/bitlist.go diff --git a/cl/cltypes/solid/bitlist.go b/cl/cltypes/solid/bitlist.go new file mode 100644 index 00000000000..6ad12899cb6 --- /dev/null +++ b/cl/cltypes/solid/bitlist.go @@ -0,0 +1,80 @@ +package solid + +import ( + "github.com/ledgerwatch/erigon/cl/merkle_tree" +) + +type bitlist struct { + u []byte + c int +} + +func NewBitList(l int, c int) BitList { + return &bitlist{ + u: make([]byte, l), + c: c, + } +} +func BitlistFromBytes(xs []byte, c int) BitList { + return &bitlist{ + u: xs, + c: c, + } +} + +func (u *bitlist) Clear() { + u.u = u.u[:0] +} + +func (u *bitlist) CopyTo(target BitList) { + target.Clear() + for _, v := range u.u { + target.Append(v) + } +} + +func (u *bitlist) Range(fn func(index int, value byte, length int) bool) { + for i, v := range u.u { + fn(i, v, len(u.u)) + } +} + +func (u *bitlist) Pop() (x byte) { + x, u.u = u.u[0], u.u[1:] + return x +} + +func (u *bitlist) Append(v byte) { + u.u = append(u.u, v) +} + +func (u *bitlist) Get(index int) byte { + return u.u[index] +} + +func (u *bitlist) Set(index int, v byte) { + u.u[index] = v +} + +func (u *bitlist) Length() int { + return len(u.u) +} + +func (u *bitlist) Cap() int { + return u.c +} + +func (u *bitlist) HashSSZTo(xs []byte) error { + root, err := merkle_tree.BitlistRootWithLimitForState(u.u, uint64(u.c)) + if err != nil { + return err + } + copy(xs, root[:]) + return nil +} + +func (u *bitlist) EncodeSSZ(dst []byte) []byte { + buf := dst + buf = append(buf, u.u[:]...) + return buf +} diff --git a/cl/cltypes/solid/interfaces.go b/cl/cltypes/solid/interfaces.go index b9cc9fddbd4..e78902924e6 100644 --- a/cl/cltypes/solid/interfaces.go +++ b/cl/cltypes/solid/interfaces.go @@ -12,3 +12,17 @@ type Uint64Slice interface { Cap() int HashSSZTo(xs []byte) error } + +type BitList interface { + Clear() + CopyTo(BitList) + Range(fn func(index int, value byte, length int) bool) + Pop() byte + Append(v byte) + Get(index int) byte + Set(index int, v byte) + Length() int + Cap() int + EncodeSSZ(dst []byte) []byte + HashSSZTo(xs []byte) error +} diff --git a/cl/cltypes/solid/uint64slice_byte_test.go b/cl/cltypes/solid/uint64slice_byte_test.go index 1fd7545225f..235994565a7 100644 --- a/cl/cltypes/solid/uint64slice_byte_test.go +++ b/cl/cltypes/solid/uint64slice_byte_test.go @@ -1,7 +1,6 @@ package solid_test import ( - "log" "testing" "github.com/ledgerwatch/erigon/cl/cltypes/solid" @@ -28,7 +27,6 @@ func TestUint64SliceBasic(t *testing.T) { nums := []uint64{3, 2, 1} root, err := merkle_tree.Uint64ListRootWithLimit(nums, 2) require.NoError(t, err) - log.Printf("merkl tree: %x", root) - log.Printf("ours tree: %x", out) + require.EqualValues(t, root, out) } diff --git a/cl/cltypes/solid/validator.go b/cl/cltypes/solid/validator.go index 29f5fd28540..c8fcfdb1dae 100644 --- a/cl/cltypes/solid/validator.go +++ b/cl/cltypes/solid/validator.go @@ -22,6 +22,29 @@ const validatorSize = 48 + 32 + 8 + 1 + 8 + 8 + 8 + 8 type Validator [validatorSize]byte +func NewValidatorFromParameters( + PublicKey [48]byte, + WithdrawalCredentials [32]byte, + EffectiveBalance uint64, + Slashed bool, + ActivationEligibilityEpoch uint64, + ActivationEpoch uint64, + ExitEpoch uint64, + WithdrawableEpoch uint64, +) *Validator { + v := &Validator{} + v.SetPublicKey(PublicKey) + v.SetWithdrawalCredentials(WithdrawalCredentials) + v.SetEffectiveBalance(EffectiveBalance) + v.SetSlashed(Slashed) + v.SetActivationEligibilityEpoch(ActivationEligibilityEpoch) + v.SetActivationEpoch(ActivationEpoch) + v.SetExitEpoch(ExitEpoch) + v.SetWithdrawableEpoch(WithdrawableEpoch) + return v + +} + func (v *Validator) CopyTo(dst *Validator) { copy(dst[:], v[:]) } diff --git a/cl/cltypes/validator_test.go b/cl/cltypes/validator_test.go index 90c0a94d1e2..ef17f25a99e 100644 --- a/cl/cltypes/validator_test.go +++ b/cl/cltypes/validator_test.go @@ -6,6 +6,7 @@ import ( "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon/cl/cltypes" + "github.com/ledgerwatch/erigon/cl/cltypes/solid" "github.com/ledgerwatch/erigon/cl/utils" "github.com/stretchr/testify/require" ) @@ -26,27 +27,27 @@ func hex2BlsPublicKey(s string) (k [48]byte) { return } -var testValidator1 = &cltypes.Validator{ - PublicKey: hex2BlsPublicKey("227a72a5b99042650eaa52ed66ebf50d31595dba2cbc3da3810378c6fa92c25b93fa0e652a1ac298549cceb6c40d6fc2"), - WithdrawalCredentials: common.HexToHash("401ef8ad032de7a3b8a50ae67cd823b0944d2260cd0d018e710eebf8e832b021"), - EffectiveBalance: 13619341603830475769, - Slashed: true, - ActivationEligibilityEpoch: 2719404809456332213, - ActivationEpoch: 8707665390408467486, - ExitEpoch: 6929014573432656651, - WithdrawableEpoch: 3085466968797960434, -} +var testValidator1 = solid.NewValidatorFromParameters( + hex2BlsPublicKey("227a72a5b99042650eaa52ed66ebf50d31595dba2cbc3da3810378c6fa92c25b93fa0e652a1ac298549cceb6c40d6fc2"), + common.HexToHash("401ef8ad032de7a3b8a50ae67cd823b0944d2260cd0d018e710eebf8e832b021"), + 13619341603830475769, + true, + 2719404809456332213, + 8707665390408467486, + 6929014573432656651, + 3085466968797960434, +) -var testValidator2 = &cltypes.Validator{ - PublicKey: hex2BlsPublicKey("bff465728708cccd057fa4be1bf83eb42ec6a70e52cca2d24309de9e2b0cbc1a7110b92e8c7f475625d1e79f86f31a3e"), - WithdrawalCredentials: common.HexToHash("3ba9e58ab7d3807a2733e3aa204fdacde3f0d16e7126492c72fa228eae20c5eb"), - EffectiveBalance: 4748534886993468932, - Slashed: false, - ActivationEligibilityEpoch: 9720109592954569431, - ActivationEpoch: 16116572433788512122, - ExitEpoch: 12361131058646161796, - WithdrawableEpoch: 8134858776785446209, -} +var testValidator2 = solid.NewValidatorFromParameters( + hex2BlsPublicKey("bff465728708cccd057fa4be1bf83eb42ec6a70e52cca2d24309de9e2b0cbc1a7110b92e8c7f475625d1e79f86f31a3e"), + common.HexToHash("3ba9e58ab7d3807a2733e3aa204fdacde3f0d16e7126492c72fa228eae20c5eb"), + 4748534886993468932, + false, + 9720109592954569431, + 16116572433788512122, + 12361131058646161796, + 8134858776785446209, +) var testValidator2Snappified, _ = hex.DecodeString("79f078bff465728708cccd057fa4be1bf83eb42ec6a70e52cca2d24309de9e2b0cbc1a7110b92e8c7f475625d1e79f86f31a3e3ba9e58ab7d3807a2733e3aa204fdacde3f0d16e7126492c72fa228eae20c5eb049ecb26522fe64100d782ece92cc4e4867a27d1403d91a9df8419a7ac348f8bab41e54308f5d2e470") @@ -54,7 +55,7 @@ var testValidatorRoot1 = common.HexToHash("83e755dbe8b552c628677bcad4d5f28b29f9a var testValidatorRoot2 = common.HexToHash("0bcf6f6b165f8ba4a0b59fad23195a83097cdfc62eca06d6219d5699f057aa14") func TestValidatorSlashed(t *testing.T) { - encoded, _ := testValidator1.EncodeSSZ([]byte{0x2}) + encoded := testValidator1.EncodeSSZ([]byte{0x2}) decodedValidator := &cltypes.Validator{} require.NoError(t, decodedValidator.DecodeSSZ(encoded[1:], 0)) root, err := decodedValidator.HashSSZ() @@ -67,8 +68,8 @@ func TestValidatorNonSlashed(t *testing.T) { decodedValidator := &cltypes.Validator{} require.NoError(t, decodedValidator.DecodeSSZ(encoded, 0)) encoded2, _ := decodedValidator.EncodeSSZ(nil) - require.Equal(t, encoded2, encoded) - require.Equal(t, decodedValidator, testValidator2) + require.EqualValues(t, encoded2, encoded) + require.EqualValues(t, decodedValidator.Validator, *testValidator2) root, err := decodedValidator.HashSSZ() require.NoError(t, err) require.Equal(t, common.Hash(root), testValidatorRoot2) diff --git a/cmd/erigon-cl/core/state/accessors.go b/cmd/erigon-cl/core/state/accessors.go index 6745db671ea..8af6b71bec9 100644 --- a/cmd/erigon-cl/core/state/accessors.go +++ b/cmd/erigon-cl/core/state/accessors.go @@ -7,6 +7,7 @@ import ( libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon/cl/clparams" "github.com/ledgerwatch/erigon/cl/cltypes" + "github.com/ledgerwatch/erigon/cl/cltypes/solid" "github.com/ledgerwatch/erigon/cl/fork" "github.com/ledgerwatch/erigon/cl/utils" "github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state/raw" @@ -86,7 +87,7 @@ func IsUnslashedParticipatingIndex(b *raw.BeaconState, epoch, index uint64, flag if err != nil { return false } - return validator.Active(epoch) && b.EpochParticipation(false)[index].HasFlag(flagIdx) && !validator.Slashed() + return validator.Active(epoch) && cltypes.ParticipationFlags(b.EpochParticipation(false).Get(int(index))).HasFlag(flagIdx) && !validator.Slashed() } // EligibleValidatorsIndicies Implementation of get_eligible_validator_indices as defined in the eth 2.0 specs. @@ -141,7 +142,7 @@ func IsValidIndexedAttestation(b *raw.BeaconState, att *cltypes.IndexedAttestati // getUnslashedParticipatingIndices returns set of currently unslashed participating indexes func GetUnslashedParticipatingIndices(b *raw.BeaconState, flagIndex int, epoch uint64) (validatorSet []uint64, err error) { - var participation cltypes.ParticipationFlagsList + var participation solid.BitList // Must be either previous or current epoch switch epoch { case Epoch(b): @@ -154,7 +155,7 @@ func GetUnslashedParticipatingIndices(b *raw.BeaconState, flagIndex int, epoch u // Iterate over all validators and include the active ones that have flag_index enabled and are not slashed. b.ForEachValidator(func(validator *cltypes.Validator, i, total int) bool { if !validator.Active(epoch) || - !participation[i].HasFlag(flagIndex) || + !cltypes.ParticipationFlags(participation.Get(i)).HasFlag(flagIndex) || validator.Slashed() { return true } diff --git a/cmd/erigon-cl/core/state/raw/copy.go b/cmd/erigon-cl/core/state/raw/copy.go index 36c2ea14863..7dfb7d155cc 100644 --- a/cmd/erigon-cl/core/state/raw/copy.go +++ b/cmd/erigon-cl/core/state/raw/copy.go @@ -35,8 +35,8 @@ func (b *BeaconState) CopyInto(dst *BeaconState) error { b.balances.CopyTo(dst.balances) copy(dst.randaoMixes[:], b.randaoMixes[:]) copy(dst.slashings[:], b.slashings[:]) - dst.previousEpochParticipation = b.previousEpochParticipation.Copy() - dst.currentEpochParticipation = b.currentEpochParticipation.Copy() + b.previousEpochParticipation.CopyTo(dst.previousEpochParticipation) + b.currentEpochParticipation.CopyTo(dst.currentEpochParticipation) dst.finalizedCheckpoint = b.finalizedCheckpoint.Copy() dst.currentJustifiedCheckpoint = b.currentJustifiedCheckpoint.Copy() dst.previousJustifiedCheckpoint = b.previousJustifiedCheckpoint.Copy() diff --git a/cmd/erigon-cl/core/state/raw/getters.go b/cmd/erigon-cl/core/state/raw/getters.go index c9eecf34a34..3e73c7698ab 100644 --- a/cmd/erigon-cl/core/state/raw/getters.go +++ b/cmd/erigon-cl/core/state/raw/getters.go @@ -7,6 +7,7 @@ import ( libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon/cl/clparams" "github.com/ledgerwatch/erigon/cl/cltypes" + "github.com/ledgerwatch/erigon/cl/cltypes/solid" "github.com/ledgerwatch/erigon/cl/fork" ) @@ -165,7 +166,7 @@ func (b *BeaconState) SlashingSegmentAt(pos int) uint64 { return b.slashings[pos] } -func (b *BeaconState) EpochParticipation(currentEpoch bool) cltypes.ParticipationFlagsList { +func (b *BeaconState) EpochParticipation(currentEpoch bool) solid.BitList { if currentEpoch { return b.currentEpochParticipation } @@ -178,9 +179,9 @@ func (b *BeaconState) JustificationBits() cltypes.JustificationBits { func (b *BeaconState) EpochParticipationForValidatorIndex(isCurrentEpoch bool, index int) cltypes.ParticipationFlags { if isCurrentEpoch { - return b.currentEpochParticipation[index] + return cltypes.ParticipationFlags(b.currentEpochParticipation.Get(index)) } - return b.previousEpochParticipation[index] + return cltypes.ParticipationFlags(b.previousEpochParticipation.Get(index)) } func (b *BeaconState) PreviousJustifiedCheckpoint() *cltypes.Checkpoint { diff --git a/cmd/erigon-cl/core/state/raw/hashing.go b/cmd/erigon-cl/core/state/raw/hashing.go index ecc44459e59..2ffe240c230 100644 --- a/cmd/erigon-cl/core/state/raw/hashing.go +++ b/cmd/erigon-cl/core/state/raw/hashing.go @@ -162,7 +162,7 @@ func (b *BeaconState) computeDirtyLeaves() error { if b.version == clparams.Phase0Version { root, err = merkle_tree.ListObjectSSZRoot(b.previousEpochAttestations, b.beaconConfig.SlotsPerEpoch*b.beaconConfig.MaxAttestations) } else { - root, err = merkle_tree.BitlistRootWithLimitForState(b.previousEpochParticipation.Bytes(), state_encoding.ValidatorRegistryLimit) + err = b.previousEpochParticipation.HashSSZTo(root[:]) } if err != nil { return err @@ -178,7 +178,7 @@ func (b *BeaconState) computeDirtyLeaves() error { if b.version == clparams.Phase0Version { root, err = merkle_tree.ListObjectSSZRoot(b.currentEpochAttestations, b.beaconConfig.SlotsPerEpoch*b.beaconConfig.MaxAttestations) } else { - root, err = merkle_tree.BitlistRootWithLimitForState(b.currentEpochParticipation.Bytes(), state_encoding.ValidatorRegistryLimit) + err = b.currentEpochParticipation.HashSSZTo(root[:]) } if err != nil { return err diff --git a/cmd/erigon-cl/core/state/raw/setters.go b/cmd/erigon-cl/core/state/raw/setters.go index 965e7a260e5..8265a91573f 100644 --- a/cmd/erigon-cl/core/state/raw/setters.go +++ b/cmd/erigon-cl/core/state/raw/setters.go @@ -4,6 +4,8 @@ import ( libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon/cl/clparams" "github.com/ledgerwatch/erigon/cl/cltypes" + "github.com/ledgerwatch/erigon/cl/cltypes/solid" + "github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state/state_encoding" ) func (b *BeaconState) SetVersion(version clparams.StateVersion) { @@ -221,11 +223,11 @@ func (b *BeaconState) IncrementSlashingSegmentAt(index int, delta uint64) { func (b *BeaconState) SetEpochParticipationForValidatorIndex(isCurrentEpoch bool, index int, flags cltypes.ParticipationFlags) { if isCurrentEpoch { b.markLeaf(CurrentEpochParticipationLeafIndex) - b.currentEpochParticipation[index] = flags + b.currentEpochParticipation.Set(index, byte(flags)) return } b.markLeaf(PreviousEpochParticipationLeafIndex) - b.previousEpochParticipation[index] = flags + b.previousEpochParticipation.Set(index, byte(flags)) } func (b *BeaconState) SetValidatorAtIndex(index int, validator *cltypes.Validator) { @@ -235,7 +237,7 @@ func (b *BeaconState) SetValidatorAtIndex(index int, validator *cltypes.Validato func (b *BeaconState) ResetEpochParticipation() { b.previousEpochParticipation = b.currentEpochParticipation - b.currentEpochParticipation = make(cltypes.ParticipationFlagsList, len(b.validators)) + b.currentEpochParticipation = solid.NewBitList(len(b.validators), state_encoding.ValidatorRegistryLimit) b.markLeaf(CurrentEpochParticipationLeafIndex) b.markLeaf(PreviousEpochParticipationLeafIndex) } @@ -323,26 +325,32 @@ func (b *BeaconState) SetValidatorInactivityScore(index int, score uint64) error func (b *BeaconState) SetCurrentEpochParticipationFlags(flags []cltypes.ParticipationFlags) { b.markLeaf(CurrentEpochParticipationLeafIndex) - b.currentEpochParticipation = flags + b.currentEpochParticipation.Clear() + for _, v := range flags { + b.currentEpochParticipation.Append(byte(v)) + } } func (b *BeaconState) SetPreviousEpochParticipationFlags(flags []cltypes.ParticipationFlags) { b.markLeaf(PreviousEpochParticipationLeafIndex) - b.previousEpochParticipation = flags + for _, v := range flags { + b.previousEpochParticipation.Append(byte(v)) + } } func (b *BeaconState) AddCurrentEpochParticipationFlags(flags cltypes.ParticipationFlags) { b.markLeaf(CurrentEpochParticipationLeafIndex) - b.currentEpochParticipation = append(b.currentEpochParticipation, flags) + b.currentEpochParticipation.Append(byte(flags)) } func (b *BeaconState) AddPreviousEpochParticipationFlags(flags cltypes.ParticipationFlags) { b.markLeaf(PreviousEpochParticipationLeafIndex) - b.previousEpochParticipation = append(b.previousEpochParticipation, flags) + b.previousEpochParticipation.Append(byte(flags)) } func (b *BeaconState) AddPreviousEpochParticipationAt(index int, delta byte) { b.markLeaf(PreviousEpochParticipationLeafIndex) - b.previousEpochParticipation[index] = b.previousEpochParticipation[index].Add(int(delta)) + tmp := b.previousEpochParticipation.Get(index) + delta + b.previousEpochParticipation.Set(index, tmp) } // phase0 fields diff --git a/cmd/erigon-cl/core/state/raw/ssz.go b/cmd/erigon-cl/core/state/raw/ssz.go index fd923552a2e..c44f9595cc2 100644 --- a/cmd/erigon-cl/core/state/raw/ssz.go +++ b/cmd/erigon-cl/core/state/raw/ssz.go @@ -7,6 +7,7 @@ import ( "github.com/ledgerwatch/erigon/cl/clparams" "github.com/ledgerwatch/erigon/cl/cltypes" "github.com/ledgerwatch/erigon/cl/cltypes/clonable" + "github.com/ledgerwatch/erigon/cl/cltypes/solid" "github.com/ledgerwatch/erigon/cl/cltypes/ssz" "github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state/state_encoding" ) @@ -71,7 +72,7 @@ func (b *BeaconState) EncodeSSZ(buf []byte) ([]byte, error) { } maxEpochAttestations := int(b.beaconConfig.SlotsPerEpoch * b.beaconConfig.MaxAttestations) - if b.version != clparams.Phase0Version && len(b.previousEpochParticipation) > state_encoding.ValidatorRegistryLimit || len(b.currentEpochParticipation) > state_encoding.ValidatorRegistryLimit { + if b.version != clparams.Phase0Version && b.previousEpochParticipation.Length() > state_encoding.ValidatorRegistryLimit || (b.currentEpochParticipation.Length()) > state_encoding.ValidatorRegistryLimit { return nil, fmt.Errorf("too many participations") } @@ -142,7 +143,7 @@ func (b *BeaconState) EncodeSSZ(buf []byte) ([]byte, error) { offset += uint32(attestation.EncodingSizeSSZ()) + 4 } } else { - offset += uint32(len(b.previousEpochParticipation)) + offset += uint32(b.previousEpochParticipation.Length()) } // current participation offset dst = append(dst, ssz.OffsetSSZ(offset)...) @@ -152,7 +153,7 @@ func (b *BeaconState) EncodeSSZ(buf []byte) ([]byte, error) { offset += uint32(attestation.EncodingSizeSSZ()) + 4 } } else { - offset += uint32(len(b.currentEpochParticipation)) + offset += uint32(b.currentEpochParticipation.Length()) } dst = append(dst, b.justificationBits.Byte()) @@ -225,8 +226,8 @@ func (b *BeaconState) EncodeSSZ(buf []byte) ([]byte, error) { return nil, err } } else { - dst = append(dst, b.previousEpochParticipation.Bytes()...) - dst = append(dst, b.currentEpochParticipation.Bytes()...) + dst = b.previousEpochParticipation.EncodeSSZ(dst) + dst = b.currentEpochParticipation.EncodeSSZ(dst) } if b.version >= clparams.AltairVersion { // write inactivity scores (offset 6) @@ -408,8 +409,8 @@ func (b *BeaconState) DecodeSSZ(buf []byte, version int) error { if currentEpochParticipation, err = ssz.DecodeString(buf, uint64(currentEpochParticipationOffset), uint64(inactivityScoresOffset), state_encoding.ValidatorRegistryLimit); err != nil { return err } - b.previousEpochParticipation, b.currentEpochParticipation = cltypes.ParticipationFlagsListFromBytes(previousEpochParticipation), cltypes.ParticipationFlagsListFromBytes(currentEpochParticipation) - + b.previousEpochParticipation = solid.BitlistFromBytes(previousEpochParticipation, state_encoding.ValidatorRegistryLimit) + b.currentEpochParticipation = solid.BitlistFromBytes(currentEpochParticipation, state_encoding.ValidatorRegistryLimit) } endOffset := uint32(len(buf)) @@ -460,8 +461,8 @@ func (b *BeaconState) EncodingSizeSSZ() (size int) { size += pendingAttestation.EncodingSizeSSZ() } } else { - size += len(b.previousEpochParticipation) - size += len(b.currentEpochParticipation) + size += b.previousEpochParticipation.Length() + size += b.currentEpochParticipation.Length() } size += b.inactivityScores.Length() * 8 diff --git a/cmd/erigon-cl/core/state/raw/state.go b/cmd/erigon-cl/core/state/raw/state.go index 1c0556cf2b3..b21aeb568fe 100644 --- a/cmd/erigon-cl/core/state/raw/state.go +++ b/cmd/erigon-cl/core/state/raw/state.go @@ -5,6 +5,7 @@ import ( "github.com/ledgerwatch/erigon/cl/clparams" "github.com/ledgerwatch/erigon/cl/cltypes" "github.com/ledgerwatch/erigon/cl/cltypes/solid" + "github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state/state_encoding" ) const ( @@ -31,8 +32,8 @@ type BeaconState struct { balances solid.Uint64Slice randaoMixes [randoMixesLength]common.Hash slashings [slashingsLength]uint64 - previousEpochParticipation cltypes.ParticipationFlagsList - currentEpochParticipation cltypes.ParticipationFlagsList + previousEpochParticipation solid.BitList + currentEpochParticipation solid.BitList justificationBits cltypes.JustificationBits // Altair previousJustifiedCheckpoint *cltypes.Checkpoint @@ -64,8 +65,10 @@ func New(cfg *clparams.BeaconChainConfig) *BeaconState { state := &BeaconState{ beaconConfig: cfg, //inactivityScores: solid.NewSimpleUint64Slice(int(cfg.ValidatorRegistryLimit)), - inactivityScores: solid.NewUint64Slice(int(cfg.ValidatorRegistryLimit)), - balances: solid.NewUint64Slice(int(cfg.ValidatorRegistryLimit)), + inactivityScores: solid.NewUint64Slice(int(cfg.ValidatorRegistryLimit)), + balances: solid.NewUint64Slice(int(cfg.ValidatorRegistryLimit)), + previousEpochParticipation: solid.NewBitList(0, int(state_encoding.ValidatorRegistryLimit)), + currentEpochParticipation: solid.NewBitList(0, int(state_encoding.ValidatorRegistryLimit)), } state.init() return state diff --git a/cmd/erigon-cl/core/transition/finalization_and_justification.go b/cmd/erigon-cl/core/transition/finalization_and_justification.go index 7b7153c173e..a92f4c526c7 100644 --- a/cmd/erigon-cl/core/transition/finalization_and_justification.go +++ b/cmd/erigon-cl/core/transition/finalization_and_justification.go @@ -91,11 +91,11 @@ func ProcessJustificationBitsAndFinality(s *state.BeaconState) error { return true } if validator.Active(previousEpoch) && - previousParticipation[i].HasFlag(int(beaconConfig.TimelyTargetFlagIndex)) { + cltypes.ParticipationFlags(previousParticipation.Get(i)).HasFlag(int(beaconConfig.TimelyTargetFlagIndex)) { previousTargetBalance += validator.EffectiveBalance() } if validator.Active(currentEpoch) && - currentParticipation[i].HasFlag(int(beaconConfig.TimelyTargetFlagIndex)) { + cltypes.ParticipationFlags(currentParticipation.Get(i)).HasFlag(int(beaconConfig.TimelyTargetFlagIndex)) { currentTargetBalance += validator.EffectiveBalance() } return true From 8cac97570a446dee115ee172b11d4163c01ca5ea Mon Sep 17 00:00:00 2001 From: a Date: Sun, 7 May 2023 07:15:15 -0500 Subject: [PATCH 05/34] forgot to reset --- cmd/erigon-cl/core/state/raw/setters.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/erigon-cl/core/state/raw/setters.go b/cmd/erigon-cl/core/state/raw/setters.go index 8265a91573f..4f48572a9d8 100644 --- a/cmd/erigon-cl/core/state/raw/setters.go +++ b/cmd/erigon-cl/core/state/raw/setters.go @@ -333,6 +333,7 @@ func (b *BeaconState) SetCurrentEpochParticipationFlags(flags []cltypes.Particip func (b *BeaconState) SetPreviousEpochParticipationFlags(flags []cltypes.ParticipationFlags) { b.markLeaf(PreviousEpochParticipationLeafIndex) + b.previousEpochParticipation.Clear() for _, v := range flags { b.previousEpochParticipation.Append(byte(v)) } From 2dad1d6cd5ff343c4fd63b99dbc139a790ec6ac5 Mon Sep 17 00:00:00 2001 From: a Date: Sun, 7 May 2023 07:54:26 -0500 Subject: [PATCH 06/34] fix addition --- cmd/ef-tests-cl/consensus_tests/sanity.go | 2 ++ cmd/erigon-cl/core/state/raw/setters.go | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cmd/ef-tests-cl/consensus_tests/sanity.go b/cmd/ef-tests-cl/consensus_tests/sanity.go index a48eeb9d0db..160c2871ba0 100644 --- a/cmd/ef-tests-cl/consensus_tests/sanity.go +++ b/cmd/ef-tests-cl/consensus_tests/sanity.go @@ -2,6 +2,7 @@ package consensus_tests import ( "io/fs" + "log" "os" "testing" @@ -62,6 +63,7 @@ var SanityBlocks = spectest.HandlerFunc(func(t *testing.T, root fs.FS, c spectes var block *cltypes.SignedBeaconBlock for _, block = range blocks { + log.Println(block) err = transition.TransitionState(testState, block, true) if err != nil { break diff --git a/cmd/erigon-cl/core/state/raw/setters.go b/cmd/erigon-cl/core/state/raw/setters.go index 4f48572a9d8..3ad800bf038 100644 --- a/cmd/erigon-cl/core/state/raw/setters.go +++ b/cmd/erigon-cl/core/state/raw/setters.go @@ -348,10 +348,11 @@ func (b *BeaconState) AddPreviousEpochParticipationFlags(flags cltypes.Participa b.markLeaf(PreviousEpochParticipationLeafIndex) b.previousEpochParticipation.Append(byte(flags)) } + func (b *BeaconState) AddPreviousEpochParticipationAt(index int, delta byte) { b.markLeaf(PreviousEpochParticipationLeafIndex) - tmp := b.previousEpochParticipation.Get(index) + delta - b.previousEpochParticipation.Set(index, tmp) + tmp := cltypes.ParticipationFlags(b.previousEpochParticipation.Get(index)).Add(int(delta)) + b.previousEpochParticipation.Set(index, byte(tmp)) } // phase0 fields From 60ff904077fae64e0ce9708047b780b97a06fb54 Mon Sep 17 00:00:00 2001 From: a Date: Sun, 7 May 2023 08:04:25 -0500 Subject: [PATCH 07/34] remove --- cmd/ef-tests-cl/consensus_tests/sanity.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmd/ef-tests-cl/consensus_tests/sanity.go b/cmd/ef-tests-cl/consensus_tests/sanity.go index 160c2871ba0..a48eeb9d0db 100644 --- a/cmd/ef-tests-cl/consensus_tests/sanity.go +++ b/cmd/ef-tests-cl/consensus_tests/sanity.go @@ -2,7 +2,6 @@ package consensus_tests import ( "io/fs" - "log" "os" "testing" @@ -63,7 +62,6 @@ var SanityBlocks = spectest.HandlerFunc(func(t *testing.T, root fs.FS, c spectes var block *cltypes.SignedBeaconBlock for _, block = range blocks { - log.Println(block) err = transition.TransitionState(testState, block, true) if err != nil { break From 060107844629a2a834ed90316dc42d84d35d424d Mon Sep 17 00:00:00 2001 From: a Date: Sun, 7 May 2023 08:52:14 -0500 Subject: [PATCH 08/34] a --- cl/cltypes/solid/bitlist.go | 2 +- cmd/ef-tests-cl/consensus_tests/sanity.go | 2 ++ cmd/erigon-cl/core/state/raw/getters.go | 4 ++++ cmd/erigon-cl/core/state/raw/ssz.go | 10 ++++++++-- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/cl/cltypes/solid/bitlist.go b/cl/cltypes/solid/bitlist.go index 6ad12899cb6..b872c20ec69 100644 --- a/cl/cltypes/solid/bitlist.go +++ b/cl/cltypes/solid/bitlist.go @@ -75,6 +75,6 @@ func (u *bitlist) HashSSZTo(xs []byte) error { func (u *bitlist) EncodeSSZ(dst []byte) []byte { buf := dst - buf = append(buf, u.u[:]...) + buf = append(buf, u.u...) return buf } diff --git a/cmd/ef-tests-cl/consensus_tests/sanity.go b/cmd/ef-tests-cl/consensus_tests/sanity.go index a48eeb9d0db..067a492485c 100644 --- a/cmd/ef-tests-cl/consensus_tests/sanity.go +++ b/cmd/ef-tests-cl/consensus_tests/sanity.go @@ -55,6 +55,8 @@ var SanityBlocks = spectest.HandlerFunc(func(t *testing.T, root fs.FS, c spectes expectedState, err := spectest.ReadBeaconState(root, c.Version(), spectest.PostSsz) if os.IsNotExist(err) { expectedError = true + } else { + require.NoError(t, err) } blocks, err := spectest.ReadBlocks(root, c.Version()) diff --git a/cmd/erigon-cl/core/state/raw/getters.go b/cmd/erigon-cl/core/state/raw/getters.go index 3e73c7698ab..17297390dfa 100644 --- a/cmd/erigon-cl/core/state/raw/getters.go +++ b/cmd/erigon-cl/core/state/raw/getters.go @@ -260,3 +260,7 @@ func (b *BeaconState) GetDomain(domainType [4]byte, epoch uint64) ([]byte, error } return fork.ComputeDomain(domainType[:], b.fork.CurrentVersion, b.genesisValidatorsRoot) } + +func (b *BeaconState) DebugPrint(prefix string) { + fmt.Printf("%s: %x\n", prefix, b.currentEpochParticipation) +} diff --git a/cmd/erigon-cl/core/state/raw/ssz.go b/cmd/erigon-cl/core/state/raw/ssz.go index c44f9595cc2..90a3ee99be0 100644 --- a/cmd/erigon-cl/core/state/raw/ssz.go +++ b/cmd/erigon-cl/core/state/raw/ssz.go @@ -409,8 +409,14 @@ func (b *BeaconState) DecodeSSZ(buf []byte, version int) error { if currentEpochParticipation, err = ssz.DecodeString(buf, uint64(currentEpochParticipationOffset), uint64(inactivityScoresOffset), state_encoding.ValidatorRegistryLimit); err != nil { return err } - b.previousEpochParticipation = solid.BitlistFromBytes(previousEpochParticipation, state_encoding.ValidatorRegistryLimit) - b.currentEpochParticipation = solid.BitlistFromBytes(currentEpochParticipation, state_encoding.ValidatorRegistryLimit) + previousEpochParticipationCopy := make([]byte, len(previousEpochParticipation)) + copy(previousEpochParticipationCopy, previousEpochParticipation) + + currentEpochParticipationCopy := make([]byte, len(currentEpochParticipation)) + copy(currentEpochParticipationCopy, currentEpochParticipation) + + b.previousEpochParticipation = solid.BitlistFromBytes(previousEpochParticipationCopy, state_encoding.ValidatorRegistryLimit) + b.currentEpochParticipation = solid.BitlistFromBytes(currentEpochParticipationCopy, state_encoding.ValidatorRegistryLimit) } endOffset := uint32(len(buf)) From aedd1f8690730d152844e4df63d8308aaff6ea22 Mon Sep 17 00:00:00 2001 From: a Date: Sun, 7 May 2023 09:11:26 -0500 Subject: [PATCH 09/34] pass the spec tests --- cl/cltypes/solid/bitlist.go | 61 ++++++++++++++++++++++++---- cl/cltypes/solid/hashutil.go | 35 ++++++---------- cl/cltypes/solid/uint64slice_byte.go | 17 +++----- 3 files changed, 70 insertions(+), 43 deletions(-) diff --git a/cl/cltypes/solid/bitlist.go b/cl/cltypes/solid/bitlist.go index b872c20ec69..64b295a6fda 100644 --- a/cl/cltypes/solid/bitlist.go +++ b/cl/cltypes/solid/bitlist.go @@ -2,28 +2,36 @@ package solid import ( "github.com/ledgerwatch/erigon/cl/merkle_tree" + "github.com/ledgerwatch/erigon/cl/utils" + "github.com/prysmaticlabs/gohashtree" ) type bitlist struct { u []byte c int + l int + + hashBuf } func NewBitList(l int, c int) BitList { return &bitlist{ - u: make([]byte, l), + u: make([]byte, l+32), + l: l, c: c, } } func BitlistFromBytes(xs []byte, c int) BitList { return &bitlist{ u: xs, + l: len(xs), c: c, } } func (u *bitlist) Clear() { u.u = u.u[:0] + u.l = 0 } func (u *bitlist) CopyTo(target BitList) { @@ -41,11 +49,16 @@ func (u *bitlist) Range(fn func(index int, value byte, length int) bool) { func (u *bitlist) Pop() (x byte) { x, u.u = u.u[0], u.u[1:] + u.l = u.l - 1 return x } func (u *bitlist) Append(v byte) { - u.u = append(u.u, v) + if len(u.u) <= u.l { + u.u = append(u.u, make([]byte, 32)...) + } + u.u[u.l] = v + u.l = u.l + 1 } func (u *bitlist) Get(index int) byte { @@ -57,7 +70,7 @@ func (u *bitlist) Set(index int, v byte) { } func (u *bitlist) Length() int { - return len(u.u) + return u.l } func (u *bitlist) Cap() int { @@ -65,16 +78,48 @@ func (u *bitlist) Cap() int { } func (u *bitlist) HashSSZTo(xs []byte) error { - root, err := merkle_tree.BitlistRootWithLimitForState(u.u, uint64(u.c)) - if err != nil { - return err + depth := getDepth((uint64(u.c) + 31) / 32) + baseRoot := [32]byte{} + if u.l == 0 { + copy(baseRoot[:], merkle_tree.ZeroHashes[depth][:]) + } else { + err := u.getBaseHash(baseRoot[:]) + if err != nil { + return err + } + } + lengthRoot := merkle_tree.Uint64Root(uint64(u.l)) + ans := utils.Keccak256(baseRoot[:], lengthRoot[:]) + copy(xs, ans[:]) + return nil +} + +func (arr *bitlist) getBaseHash(xs []byte) error { + depth := getDepth((uint64(arr.c) + 31) / 32) + offset := 32*(arr.l/32) + 32 + if len(arr.u) <= offset { + arr.u = append(arr.u, make([]byte, offset-len(arr.u))...) + } + elements := arr.u[:offset] + for i := uint8(0); i < depth; i++ { + // Sequential + layerLen := len(elements) + if layerLen%64 == 32 { + elements = append(elements, merkle_tree.ZeroHashes[i][:]...) + } + outputLen := len(elements) / 2 + arr.makeBuf(outputLen) + if err := gohashtree.HashByteSlice(arr.buf, elements); err != nil { + return err + } + elements = arr.buf } - copy(xs, root[:]) + copy(xs, elements[:32]) return nil } func (u *bitlist) EncodeSSZ(dst []byte) []byte { buf := dst - buf = append(buf, u.u...) + buf = append(buf, u.u[:u.l]...) return buf } diff --git a/cl/cltypes/solid/hashutil.go b/cl/cltypes/solid/hashutil.go index 39a66233c31..f979013e7b7 100644 --- a/cl/cltypes/solid/hashutil.go +++ b/cl/cltypes/solid/hashutil.go @@ -8,6 +8,18 @@ import ( "github.com/prysmaticlabs/gohashtree" ) +type hashBuf struct { + buf []byte +} + +func (arr *hashBuf) makeBuf(size int) { + diff := size - len(arr.buf) + if diff > 0 { + arr.buf = append(arr.buf, make([]byte, diff)...) + } + arr.buf = arr.buf[:size] +} + func TreeHashFlatSlice(input []byte, res []byte) (err error) { err = merkle_tree.MerkleRootFromFlatLeaves(input, res) if err != nil { @@ -16,29 +28,6 @@ func TreeHashFlatSlice(input []byte, res []byte) (err error) { return nil } -// MerkleizeVector uses our optimized routine to hash a list of 32-byte -// elements. -func MerkleizeVector(elements [][32]byte, length uint64) ([32]byte, error) { - depth := getDepth(length) - // Return zerohash at depth - if len(elements) == 0 { - return merkle_tree.ZeroHashes[depth], nil - } - for i := uint8(0); i < depth; i++ { - // Sequential - layerLen := len(elements) - if layerLen%2 == 1 { - elements = append(elements, merkle_tree.ZeroHashes[i]) - } - outputLen := len(elements) / 2 - if err := gohashtree.Hash(elements, elements); err != nil { - return [32]byte{}, err - } - elements = elements[:outputLen] - } - return elements[0], nil -} - // MerkleizeVector uses our optimized routine to hash a list of 32-byte // elements. func MerkleizeFlatLeaves(elements []byte) ([]byte, error) { diff --git a/cl/cltypes/solid/uint64slice_byte.go b/cl/cltypes/solid/uint64slice_byte.go index a1dbae3a945..33f10eb3f0f 100644 --- a/cl/cltypes/solid/uint64slice_byte.go +++ b/cl/cltypes/solid/uint64slice_byte.go @@ -9,11 +9,12 @@ import ( ) type byteBasedUint64Slice struct { - u []byte - hashBuf []byte + u []byte l int // len c int // cap + + hashBuf } func NewUint64Slice(limit int) Uint64Slice { @@ -72,14 +73,6 @@ func (arr *byteBasedUint64Slice) Pop() uint64 { return val } -func (arr *byteBasedUint64Slice) makeBuf(size int) { - diff := size - len(arr.hashBuf) - if diff > 0 { - arr.hashBuf = append(arr.hashBuf, make([]byte, diff)...) - } - arr.hashBuf = arr.hashBuf[:size] -} - func (arr *byteBasedUint64Slice) Append(v uint64) { if len(arr.u) <= arr.l*8 { arr.u = append(arr.u, make([]byte, 32)...) @@ -142,10 +135,10 @@ func (arr *byteBasedUint64Slice) getBaseHash(xs []byte) error { } outputLen := len(elements) / 2 arr.makeBuf(outputLen) - if err := gohashtree.HashByteSlice(arr.hashBuf, elements); err != nil { + if err := gohashtree.HashByteSlice(arr.buf, elements); err != nil { return err } - elements = arr.hashBuf + elements = arr.buf } copy(xs, elements[:32]) return nil From f50a99fd08fbd4cd30095ad0efe176369df5d2f9 Mon Sep 17 00:00:00 2001 From: a Date: Sun, 7 May 2023 09:12:27 -0500 Subject: [PATCH 10/34] simplify --- cl/cltypes/solid/bitlist.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cl/cltypes/solid/bitlist.go b/cl/cltypes/solid/bitlist.go index 64b295a6fda..131fdb13f20 100644 --- a/cl/cltypes/solid/bitlist.go +++ b/cl/cltypes/solid/bitlist.go @@ -83,7 +83,7 @@ func (u *bitlist) HashSSZTo(xs []byte) error { if u.l == 0 { copy(baseRoot[:], merkle_tree.ZeroHashes[depth][:]) } else { - err := u.getBaseHash(baseRoot[:]) + err := u.getBaseHash(baseRoot[:], depth) if err != nil { return err } @@ -94,8 +94,7 @@ func (u *bitlist) HashSSZTo(xs []byte) error { return nil } -func (arr *bitlist) getBaseHash(xs []byte) error { - depth := getDepth((uint64(arr.c) + 31) / 32) +func (arr *bitlist) getBaseHash(xs []byte, depth uint8) error { offset := 32*(arr.l/32) + 32 if len(arr.u) <= offset { arr.u = append(arr.u, make([]byte, offset-len(arr.u))...) From 8897a9e258698ebc6d87f8c22386ec21c09b03dc Mon Sep 17 00:00:00 2001 From: a Date: Sun, 7 May 2023 09:16:10 -0500 Subject: [PATCH 11/34] merge --- cmd/caplin-phase1/caplin1/run.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/caplin-phase1/caplin1/run.go b/cmd/caplin-phase1/caplin1/run.go index 9d4738faf4d..f85cf38e826 100644 --- a/cmd/caplin-phase1/caplin1/run.go +++ b/cmd/caplin-phase1/caplin1/run.go @@ -29,7 +29,8 @@ func RunCaplinPhase1(ctx context.Context, sentinel sentinel.SentinelClient, beac } bls.SetEnabledCaching(true) state.ForEachValidator(func(v *cltypes.Validator, idx, total int) bool { - if err := bls.LoadPublicKeyIntoCache(v.PublicKey[:], false); err != nil { + pk := v.PublicKey() + if err := bls.LoadPublicKeyIntoCache(pk[:], false); err != nil { panic(err) } return true From ce99bc4b3296f840fcac08b84617ca3143385b93 Mon Sep 17 00:00:00 2001 From: a Date: Sun, 7 May 2023 09:22:58 -0500 Subject: [PATCH 12/34] caplin --- cmd/caplin-phase1/main.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd/caplin-phase1/main.go b/cmd/caplin-phase1/main.go index 656a05ba265..bff11cbfd1e 100644 --- a/cmd/caplin-phase1/main.go +++ b/cmd/caplin-phase1/main.go @@ -33,6 +33,7 @@ import ( "github.com/ledgerwatch/erigon/cmd/sentinel/sentinel" "github.com/ledgerwatch/erigon/cmd/sentinel/sentinel/service" lightclientapp "github.com/ledgerwatch/erigon/turbo/app" + "github.com/ledgerwatch/erigon/turbo/debug" ) func main() { @@ -52,6 +53,9 @@ func runCaplinNode(cliCtx *cli.Context) error { if err != nil { log.Error("[Phase1] Could not initialize caplin", "err", err) } + if _, err := debug.Setup(cliCtx, true /* root logger */); err != nil { + return err + } log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(cfg.LogLvl), log.StderrHandler)) log.Info("[Phase1]", "chain", cliCtx.String(flags.Chain.Name)) log.Info("[Phase1] Running Caplin", "cfg", cfg) From ee33d8e4035372226a2971fe339dd0d22bbbd26f Mon Sep 17 00:00:00 2001 From: a Date: Tue, 9 May 2023 10:02:41 -0500 Subject: [PATCH 13/34] fix some tests --- cmd/erigon-cl/core/state/raw/state.go | 5 +- cmd/erigon-cl/core/state/raw/test_util.go | 2 + .../core/transition/operations_test.go | 51 +++++++++---------- .../core/transition/process_slots_test.go | 10 +++- .../process_sync_committee_update_test.go | 6 ++- .../core/transition/processing_test.go | 12 ++--- 6 files changed, 47 insertions(+), 39 deletions(-) diff --git a/cmd/erigon-cl/core/state/raw/state.go b/cmd/erigon-cl/core/state/raw/state.go index b21aeb568fe..daa2f677dad 100644 --- a/cmd/erigon-cl/core/state/raw/state.go +++ b/cmd/erigon-cl/core/state/raw/state.go @@ -5,7 +5,6 @@ import ( "github.com/ledgerwatch/erigon/cl/clparams" "github.com/ledgerwatch/erigon/cl/cltypes" "github.com/ledgerwatch/erigon/cl/cltypes/solid" - "github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state/state_encoding" ) const ( @@ -67,8 +66,8 @@ func New(cfg *clparams.BeaconChainConfig) *BeaconState { //inactivityScores: solid.NewSimpleUint64Slice(int(cfg.ValidatorRegistryLimit)), inactivityScores: solid.NewUint64Slice(int(cfg.ValidatorRegistryLimit)), balances: solid.NewUint64Slice(int(cfg.ValidatorRegistryLimit)), - previousEpochParticipation: solid.NewBitList(0, int(state_encoding.ValidatorRegistryLimit)), - currentEpochParticipation: solid.NewBitList(0, int(state_encoding.ValidatorRegistryLimit)), + previousEpochParticipation: solid.NewBitList(0, int(cfg.ValidatorRegistryLimit)), + currentEpochParticipation: solid.NewBitList(0, int(cfg.ValidatorRegistryLimit)), } state.init() return state diff --git a/cmd/erigon-cl/core/state/raw/test_util.go b/cmd/erigon-cl/core/state/raw/test_util.go index 78b251cace6..f0a2aa44cc8 100644 --- a/cmd/erigon-cl/core/state/raw/test_util.go +++ b/cmd/erigon-cl/core/state/raw/test_util.go @@ -26,6 +26,8 @@ func GetEmptyBeaconState() *BeaconState { beaconConfig: cfg, inactivityScores: solid.NewUint64Slice(int(cfg.ValidatorRegistryLimit)), balances: solid.NewUint64Slice(int(cfg.ValidatorRegistryLimit)), + previousEpochParticipation: solid.NewBitList(0, int(cfg.ValidatorRegistryLimit)), + currentEpochParticipation: solid.NewBitList(0, int(cfg.ValidatorRegistryLimit)), } b.init() return b diff --git a/cmd/erigon-cl/core/transition/operations_test.go b/cmd/erigon-cl/core/transition/operations_test.go index 2eedea892e6..38111efa7f2 100644 --- a/cmd/erigon-cl/core/transition/operations_test.go +++ b/cmd/erigon-cl/core/transition/operations_test.go @@ -188,36 +188,33 @@ func TestProcessProposerSlashing(t *testing.T) { func TestProcessAttesterSlashing(t *testing.T) { unchangingState := getTestState(t) - unchangingState.SetValidatorAtIndex(0, &cltypes.Validator{ - Slashed: false, - ActivationEpoch: 0, - WithdrawableEpoch: 10000, - PublicKey: testPublicKeySlashing, - }) - unchangingState.SetValidatorAtIndex(1, &cltypes.Validator{ - Slashed: false, - ActivationEpoch: 0, - WithdrawableEpoch: 10000, - PublicKey: testPublicKey2Slashing, - }) + v1 := &cltypes.Validator{} + v1.SetSlashed(false) + v1.SetActivationEpoch(0) + v1.SetWithdrawableEpoch(10000) + v1.SetPublicKey(testPublicKeySlashing) + v1c := &cltypes.Validator{} + v1.CopyTo(v1c) + + v2 := &cltypes.Validator{} + v2.SetSlashed(false) + v2.SetActivationEpoch(0) + v2.SetWithdrawableEpoch(10000) + v2.SetPublicKey(testPublicKey2Slashing) + v2c := &cltypes.Validator{} + v2.CopyTo(v2c) + + unchangingState.SetValidatorAtIndex(0, v1) + unchangingState.SetValidatorAtIndex(1, v2) successState := getTestState(t) - successState.SetValidatorAtIndex(0, &cltypes.Validator{ - Slashed: false, - ActivationEpoch: 0, - WithdrawableEpoch: 10000, - PublicKey: testPublicKeySlashing, - }) - successState.SetValidatorAtIndex(1, &cltypes.Validator{ - Slashed: false, - ActivationEpoch: 0, - WithdrawableEpoch: 10000, - PublicKey: testPublicKey2Slashing, - }) + successState.SetValidatorAtIndex(0, v1c) + successState.SetValidatorAtIndex(1, v2c) successBalances := []uint64{} - for i := 0; i < len(successState.Validators()); i++ { + successState.ForEachValidator(func(v *cltypes.Validator, i, total int) bool { successBalances = append(successBalances, uint64(i+1)) - } + return true + }) successState.SetBalances(successBalances) successSlashing := getSuccessfulAttesterSlashing() @@ -352,5 +349,5 @@ func TestProcessVoluntaryExits(t *testing.T) { require.NoError(t, ProcessVoluntaryExit(state, exit, false), "Could not process exits") newRegistry, err := state.ValidatorForValidatorIndex(0) require.NoError(t, err) - require.Equal(t, newRegistry.ExitEpoch, uint64(266)) + require.Equal(t, newRegistry.ExitEpoch(), uint64(266)) } diff --git a/cmd/erigon-cl/core/transition/process_slots_test.go b/cmd/erigon-cl/core/transition/process_slots_test.go index dc7b91549af..97eb3a9439d 100644 --- a/cmd/erigon-cl/core/transition/process_slots_test.go +++ b/cmd/erigon-cl/core/transition/process_slots_test.go @@ -130,7 +130,10 @@ func TestTransitionSlot(t *testing.T) { func TestProcessSlots(t *testing.T) { slot42 := getTestBeaconState() - slot42.AddValidator(&cltypes.Validator{ExitEpoch: clparams.MainnetBeaconConfig.FarFutureEpoch, WithdrawableEpoch: clparams.MainnetBeaconConfig.FarFutureEpoch}, 1) + v := &cltypes.Validator{} + v.SetExitEpoch(clparams.MainnetBeaconConfig.FarFutureEpoch) + v.SetWithdrawableEpoch(clparams.MainnetBeaconConfig.FarFutureEpoch) + slot42.AddValidator(v, 1) slot42.SetSlot(42) testCases := []struct { description string @@ -188,7 +191,10 @@ func TestProcessSlots(t *testing.T) { for _, tc := range testCases { t.Run(tc.description, func(t *testing.T) { - tc.prevState.AddValidator(&cltypes.Validator{ExitEpoch: clparams.MainnetBeaconConfig.FarFutureEpoch, WithdrawableEpoch: clparams.MainnetBeaconConfig.FarFutureEpoch}, 1) + v := &cltypes.Validator{} + v.SetExitEpoch(clparams.MainnetBeaconConfig.FarFutureEpoch) + v.SetWithdrawableEpoch(clparams.MainnetBeaconConfig.FarFutureEpoch) + tc.prevState.AddValidator(v, 1) err := ProcessSlots(tc.prevState, tc.startSlot+tc.numSlots) if tc.wantErr { if err == nil { diff --git a/cmd/erigon-cl/core/transition/process_sync_committee_update_test.go b/cmd/erigon-cl/core/transition/process_sync_committee_update_test.go index 96e4ddc2b78..b16260a0ccb 100644 --- a/cmd/erigon-cl/core/transition/process_sync_committee_update_test.go +++ b/cmd/erigon-cl/core/transition/process_sync_committee_update_test.go @@ -23,7 +23,11 @@ func TestProcessSyncCommittee(t *testing.T) { for i := 0; i < validatorNum; i++ { var pubKey [48]byte binary.BigEndian.PutUint64(pubKey[:], uint64(i)) - state.AddValidator(&cltypes.Validator{ExitEpoch: clparams.MainnetBeaconConfig.FarFutureEpoch, PublicKey: pk, EffectiveBalance: 2000000000}, 2000000000) + v := &cltypes.Validator{} + v.SetExitEpoch(clparams.MainnetBeaconConfig.FarFutureEpoch) + v.SetPublicKey(pk) + v.SetEffectiveBalance(2000000000) + state.AddValidator(v, 2000000000) if len(currentCommittee.PubKeys) != cltypes.SyncCommitteeSize { currentCommittee.PubKeys = append(currentCommittee.PubKeys, [48]byte{}) } else if len(nextCommittee.PubKeys) != cltypes.SyncCommitteeSize { diff --git a/cmd/erigon-cl/core/transition/processing_test.go b/cmd/erigon-cl/core/transition/processing_test.go index 6ea60b5492e..baa8266e187 100644 --- a/cmd/erigon-cl/core/transition/processing_test.go +++ b/cmd/erigon-cl/core/transition/processing_test.go @@ -24,10 +24,10 @@ func getTestState(t *testing.T) *state.BeaconState { numVals := 2048 validators := make([]*cltypes.Validator, numVals) for i := 0; i < numVals; i++ { - validators[i] = &cltypes.Validator{ - ActivationEpoch: 0, - ExitEpoch: 10000, - } + v := &cltypes.Validator{} + v.SetActivationEpoch(0) + v.SetExitEpoch(10000) + validators[i] = v } b := state.GetEmptyBeaconState() b.SetValidators(validators) @@ -85,7 +85,7 @@ func TestProcessBlockHeader(t *testing.T) { badStateSlashed := getTestState(t) validator, err := badStateSlashed.ValidatorForValidatorIndex(int(testBlock.ProposerIndex)) require.NoError(t, err) - validator.Slashed = true + validator.SetSlashed(true) badStateSlashed.SetValidatorAtIndex(int(testBlock.ProposerIndex), validator) testCases := []struct { @@ -162,7 +162,7 @@ func TestProcessRandao(t *testing.T) { } validator, err := testStateSuccess.ValidatorForValidatorIndex(int(propInd)) require.NoError(t, err) - validator.PublicKey = testPublicKeyRandao + validator.SetPublicKey(testPublicKeyRandao) testStateSuccess.SetValidatorAtIndex(int(propInd), validator) testBlock := getTestBlock(t) testBlock.Body.RandaoReveal = testSignatureRandao From 451f0e4639ab95df0afd8539a1d9904dc4f7a7a9 Mon Sep 17 00:00:00 2001 From: a Date: Tue, 9 May 2023 10:33:15 -0500 Subject: [PATCH 14/34] lint --- cl/merkle_tree/primitives.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cl/merkle_tree/primitives.go b/cl/merkle_tree/primitives.go index b8d46cc5b1c..f58ac6edce2 100644 --- a/cl/merkle_tree/primitives.go +++ b/cl/merkle_tree/primitives.go @@ -42,6 +42,5 @@ func InPlacePublicKeyRoot(key []byte) error { if err != nil { return err } - key = key[:32] return nil } From a302512db3e7a76fad3c7d96f4848db37da166a1 Mon Sep 17 00:00:00 2001 From: a Date: Tue, 9 May 2023 10:57:40 -0500 Subject: [PATCH 15/34] remove pool for now --- cl/cltypes/validator.go | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/cl/cltypes/validator.go b/cl/cltypes/validator.go index 0f8257814d0..171b30bfdb1 100644 --- a/cl/cltypes/validator.go +++ b/cl/cltypes/validator.go @@ -3,7 +3,6 @@ package cltypes import ( "bytes" "fmt" - "sync" libcommon "github.com/ledgerwatch/erigon-lib/common" @@ -332,19 +331,21 @@ func (v *Validator) DecodeSSZ(buf []byte, _ int) error { return v.Validator.DecodeSSZ(buf, 0) } -var validatorLeavesPool = sync.Pool{ - New: func() any { - p := make([]byte, 8*32) - return &p - }, -} +//var validatorLeavesPool = sync.Pool{ +// New: func() any { +// p := make([]byte, 8*32) +// return &p +// }, +//} func (v *Validator) HashSSZ() (o [32]byte, err error) { - leavesp, _ := validatorLeavesPool.Get().(*[]byte) - leaves := *leavesp - defer func() { - validatorLeavesPool.Put(leavesp) - }() + // leavesp, _ := validatorLeavesPool.Get().(*[]byte) + // leaves := *leavesp + // + // defer func() { + // validatorLeavesPool.Put(leavesp) + // }() + leaves := make([]byte, 8*32) v.CopyHashBufferTo(leaves) leaves = leaves[:(8 * 32)] err = solid.TreeHashFlatSlice(leaves, o[:]) From 14658e92dcdcdd3ef865e3a719ea1e2e0a2a02da Mon Sep 17 00:00:00 2001 From: a Date: Tue, 9 May 2023 11:57:57 -0500 Subject: [PATCH 16/34] fix test --- cmd/erigon-cl/core/transition/operations_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/erigon-cl/core/transition/operations_test.go b/cmd/erigon-cl/core/transition/operations_test.go index 38111efa7f2..e3b73ac5b40 100644 --- a/cmd/erigon-cl/core/transition/operations_test.go +++ b/cmd/erigon-cl/core/transition/operations_test.go @@ -349,5 +349,5 @@ func TestProcessVoluntaryExits(t *testing.T) { require.NoError(t, ProcessVoluntaryExit(state, exit, false), "Could not process exits") newRegistry, err := state.ValidatorForValidatorIndex(0) require.NoError(t, err) - require.Equal(t, newRegistry.ExitEpoch(), uint64(266)) + require.Equal(t, newRegistry.ExitEpoch, uint64(266)) } From e1742020dcdad9b917a1f32eb65c1f1feb70f7b3 Mon Sep 17 00:00:00 2001 From: a Date: Tue, 9 May 2023 12:00:42 -0500 Subject: [PATCH 17/34] another patch --- cmd/erigon-cl/core/transition/operations_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/erigon-cl/core/transition/operations_test.go b/cmd/erigon-cl/core/transition/operations_test.go index e3b73ac5b40..38111efa7f2 100644 --- a/cmd/erigon-cl/core/transition/operations_test.go +++ b/cmd/erigon-cl/core/transition/operations_test.go @@ -349,5 +349,5 @@ func TestProcessVoluntaryExits(t *testing.T) { require.NoError(t, ProcessVoluntaryExit(state, exit, false), "Could not process exits") newRegistry, err := state.ValidatorForValidatorIndex(0) require.NoError(t, err) - require.Equal(t, newRegistry.ExitEpoch, uint64(266)) + require.Equal(t, newRegistry.ExitEpoch(), uint64(266)) } From 33006a22c92f81edd883409d5f3365f00438f271 Mon Sep 17 00:00:00 2001 From: a Date: Tue, 9 May 2023 12:52:34 -0500 Subject: [PATCH 18/34] rever prysm, bad test to see what happens on mac os --- cl/cltypes/solid/bitlist.go | 3 +-- cl/cltypes/solid/hashutil.go | 3 +-- cl/cltypes/solid/uint64slice_byte.go | 3 +-- cl/merkle_tree/hasher.go | 33 +++++++++++++++++++++++----- cl/merkle_tree/merkle_root.go | 7 ++++++ go.mod | 2 +- go.sum | 2 ++ 7 files changed, 41 insertions(+), 12 deletions(-) diff --git a/cl/cltypes/solid/bitlist.go b/cl/cltypes/solid/bitlist.go index 131fdb13f20..b0cdcdbb025 100644 --- a/cl/cltypes/solid/bitlist.go +++ b/cl/cltypes/solid/bitlist.go @@ -3,7 +3,6 @@ package solid import ( "github.com/ledgerwatch/erigon/cl/merkle_tree" "github.com/ledgerwatch/erigon/cl/utils" - "github.com/prysmaticlabs/gohashtree" ) type bitlist struct { @@ -108,7 +107,7 @@ func (arr *bitlist) getBaseHash(xs []byte, depth uint8) error { } outputLen := len(elements) / 2 arr.makeBuf(outputLen) - if err := gohashtree.HashByteSlice(arr.buf, elements); err != nil { + if err := merkle_tree.HashByteSlice(arr.buf, elements); err != nil { return err } elements = arr.buf diff --git a/cl/cltypes/solid/hashutil.go b/cl/cltypes/solid/hashutil.go index f979013e7b7..006ff8350b6 100644 --- a/cl/cltypes/solid/hashutil.go +++ b/cl/cltypes/solid/hashutil.go @@ -5,7 +5,6 @@ import ( "github.com/ledgerwatch/erigon/cl/merkle_tree" "github.com/ledgerwatch/erigon/cl/utils" - "github.com/prysmaticlabs/gohashtree" ) type hashBuf struct { @@ -37,7 +36,7 @@ func MerkleizeFlatLeaves(elements []byte) ([]byte, error) { if !utils.IsPowerOf2(uint64(len(elements))) { return nil, fmt.Errorf("hash layer is a non power of 2: %d", len(elements)) } - if err := gohashtree.HashByteSlice(layer, elements); err != nil { + if err := merkle_tree.HashByteSlice(layer, elements); err != nil { return nil, err } elements = layer[:len(elements)/2] diff --git a/cl/cltypes/solid/uint64slice_byte.go b/cl/cltypes/solid/uint64slice_byte.go index 33f10eb3f0f..37cf7cea6a6 100644 --- a/cl/cltypes/solid/uint64slice_byte.go +++ b/cl/cltypes/solid/uint64slice_byte.go @@ -5,7 +5,6 @@ import ( "github.com/ledgerwatch/erigon/cl/merkle_tree" "github.com/ledgerwatch/erigon/cl/utils" - "github.com/prysmaticlabs/gohashtree" ) type byteBasedUint64Slice struct { @@ -135,7 +134,7 @@ func (arr *byteBasedUint64Slice) getBaseHash(xs []byte) error { } outputLen := len(elements) / 2 arr.makeBuf(outputLen) - if err := gohashtree.HashByteSlice(arr.buf, elements); err != nil { + if err := merkle_tree.HashByteSlice(arr.buf, elements); err != nil { return err } elements = arr.buf diff --git a/cl/merkle_tree/hasher.go b/cl/merkle_tree/hasher.go index 628b6c9db7e..8c2f0bc3f41 100644 --- a/cl/merkle_tree/hasher.go +++ b/cl/merkle_tree/hasher.go @@ -49,17 +49,32 @@ func (m *merkleHasher) merkleizeTrieLeaves(leaves [][32]byte) ([32]byte, error) func (m *merkleHasher) merkleizeTrieLeavesFlat(leaves []byte, out []byte) (err error) { m.mu.Lock() defer m.mu.Unlock() - layer := m.getFlatBuffer(len(leaves) / 2) - for len(leaves) > 32 { - if err := gohashtree.HashByteSlice(layer, leaves); err != nil { + layer := m.getBufferFromFlat(leaves) + for len(layer) > 1 { + if err := gohashtree.Hash(layer, layer); err != nil { return err } - leaves = layer[:len(leaves)/2] + layer = layer[:len(layer)/2] } - copy(out, leaves[:32]) + copy(out, layer[0][:]) return } +func (m *merkleHasher) hashByteSlice(out []byte, in []byte) error { + m.mu.Lock() + defer m.mu.Unlock() + l := m.getBufferFromFlat(in) + o := make([][32]byte, len(l)/2) + err := gohashtree.Hash(o, l) + if err != nil { + return err + } + for i := range o { + copy(out[i*32:(i+1)*32], o[i][:]) + } + return nil +} + // getBuffer provides buffer of given size. func (m *merkleHasher) getBuffer(size int) [][32]byte { if size > len(m.internalBuffer) { @@ -68,6 +83,14 @@ func (m *merkleHasher) getBuffer(size int) [][32]byte { return m.internalBuffer[:size] } +func (m *merkleHasher) getBufferFromFlat(xs []byte) [][32]byte { + buf := m.getBuffer(len(xs) / 32) + for i := 0; i < len(xs)/32; i = i + 1 { + copy(buf[i][:], xs[i*32:(i+1)*32]) + } + return buf +} + // getBuffer provides buffer of given size. func (m *merkleHasher) getFlatBuffer(size int) []byte { if size > len(m.internalFlatBuffer) { diff --git a/cl/merkle_tree/merkle_root.go b/cl/merkle_tree/merkle_root.go index 6ab2d05b15e..e29ebf29c51 100644 --- a/cl/merkle_tree/merkle_root.go +++ b/cl/merkle_tree/merkle_root.go @@ -4,6 +4,13 @@ import ( "errors" ) +func HashByteSlice(out, in []byte) error { + if len(in) == 0 { + return errors.New("zero leaves provided") + } + return globalHasher.hashByteSlice(out, in) +} + func MerkleRootFromLeaves(leaves [][32]byte) ([32]byte, error) { if len(leaves) == 0 { return [32]byte{}, errors.New("zero leaves provided") diff --git a/go.mod b/go.mod index 09009f89c81..96853e29efa 100644 --- a/go.mod +++ b/go.mod @@ -68,7 +68,7 @@ require ( github.com/protolambda/eth2-shuffle v1.1.0 github.com/protolambda/ztyp v0.2.2 github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 - github.com/prysmaticlabs/gohashtree v0.0.3-alpha.0.20230502123415-aafd8b3ca202 + github.com/prysmaticlabs/gohashtree v0.0.3-alpha github.com/quasilyte/go-ruleguard/dsl v0.3.22 github.com/rs/cors v1.9.0 github.com/shirou/gopsutil/v3 v3.23.4 diff --git a/go.sum b/go.sum index 187ade2f70c..354282685d9 100644 --- a/go.sum +++ b/go.sum @@ -679,6 +679,8 @@ github.com/protolambda/ztyp v0.2.2 h1:rVcL3vBu9W/aV646zF6caLS/dyn9BN8NYiuJzicLNy github.com/protolambda/ztyp v0.2.2/go.mod h1:9bYgKGqg3wJqT9ac1gI2hnVb0STQq7p/1lapqrqY1dU= github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 h1:0tVE4tdWQK9ZpYygoV7+vS6QkDvQVySboMVEIxBJmXw= github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7/go.mod h1:wmuf/mdK4VMD+jA9ThwcUKjg3a2XWM9cVfFYjDyY4j4= +github.com/prysmaticlabs/gohashtree v0.0.3-alpha h1:1EVinCWdb3Lorq7xn8DYQHf48nCcdAM3Vb18KsFlRWY= +github.com/prysmaticlabs/gohashtree v0.0.3-alpha/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk= github.com/prysmaticlabs/gohashtree v0.0.3-alpha.0.20230502123415-aafd8b3ca202 h1:ZsFouPKy81vvQo/Zup5gASVdOm6aiuwUhp7GxvQmjIA= github.com/prysmaticlabs/gohashtree v0.0.3-alpha.0.20230502123415-aafd8b3ca202/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk= github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE= From 09ca38a139ef5628034259b3bbcd7d75109a4d24 Mon Sep 17 00:00:00 2001 From: a Date: Tue, 9 May 2023 13:19:25 -0500 Subject: [PATCH 19/34] start --- cl/merkle_tree/merkle_root.go | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/cl/merkle_tree/merkle_root.go b/cl/merkle_tree/merkle_root.go index e29ebf29c51..aba4f6e18ae 100644 --- a/cl/merkle_tree/merkle_root.go +++ b/cl/merkle_tree/merkle_root.go @@ -2,13 +2,45 @@ package merkle_tree import ( "errors" + "reflect" + "unsafe" + + "github.com/prysmaticlabs/gohashtree" ) func HashByteSlice(out, in []byte) error { if len(in) == 0 { return errors.New("zero leaves provided") } - return globalHasher.hashByteSlice(out, in) + + if len(out)%32 != 0 { + return errors.New("output must be multple of 32") + } + if len(in)%64 != 0 { + return errors.New("input must be multple of 64") + } + c_in := convertHeader(in) + c_out := convertHeader(out) + err := gohashtree.Hash(c_out, c_in) + if err != nil { + return err + } + return nil +} + +func convertHeader(xs []byte) [][32]byte { + header := *(*reflect.SliceHeader)(unsafe.Pointer(&xs)) + header.Len /= 32 + header.Cap /= 32 + chunkedChunks := *(*[][32]byte)(unsafe.Pointer(&header)) + return chunkedChunks +} +func convertHeaderBack(xs [][32]byte) []byte { + header := *(*reflect.SliceHeader)(unsafe.Pointer(&xs)) + header.Len *= 32 + header.Cap *= 32 + unchunkedChunks := *(*[]byte)(unsafe.Pointer(&header)) + return unchunkedChunks } func MerkleRootFromLeaves(leaves [][32]byte) ([32]byte, error) { From cbb3c51f722b989fe8094c2599ec55228d115002 Mon Sep 17 00:00:00 2001 From: a Date: Tue, 9 May 2023 13:45:12 -0500 Subject: [PATCH 20/34] note --- cl/merkle_tree/merkle_root.go | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/cl/merkle_tree/merkle_root.go b/cl/merkle_tree/merkle_root.go index aba4f6e18ae..0a844ac3e88 100644 --- a/cl/merkle_tree/merkle_root.go +++ b/cl/merkle_tree/merkle_root.go @@ -29,18 +29,26 @@ func HashByteSlice(out, in []byte) error { } func convertHeader(xs []byte) [][32]byte { - header := *(*reflect.SliceHeader)(unsafe.Pointer(&xs)) - header.Len /= 32 - header.Cap /= 32 - chunkedChunks := *(*[][32]byte)(unsafe.Pointer(&header)) - return chunkedChunks -} -func convertHeaderBack(xs [][32]byte) []byte { - header := *(*reflect.SliceHeader)(unsafe.Pointer(&xs)) - header.Len *= 32 - header.Cap *= 32 - unchunkedChunks := *(*[]byte)(unsafe.Pointer(&header)) - return unchunkedChunks + // this commented naive method of conversion supposedly leads to corruption https://github.com/golang/go/issues/40701 + //header := *(*reflect.SliceHeader)(unsafe.Pointer(&xs)) + //header.Len /= 32 + //header.Cap /= 32 + //chunkedChunks := *(*[][32]byte)(unsafe.Pointer(&header)) + //supposedly, this is because escape analysis does not correctly analyze this, and so you have this ghost header? + + // i wont pretend to understand, but my solution for the problem is as so + + // first i grab the slice header of the input + header := (*reflect.SliceHeader)(unsafe.Pointer(&xs)) + // then i allocate a new result slice of no size - this should make the escape analyzer happy i think? + dat := make([][32]byte, 0) + // we then get the header of our output to modify + chunkedHeader := (*reflect.SliceHeader)(unsafe.Pointer(&dat)) + // then we move over the values + chunkedHeader.Len = header.Len / 32 + chunkedHeader.Cap = header.Cap / 32 + chunkedHeader.Data = header.Data + return dat } func MerkleRootFromLeaves(leaves [][32]byte) ([32]byte, error) { From 13562c5366a1f29682c13c867b5f711e26f0433b Mon Sep 17 00:00:00 2001 From: a Date: Wed, 10 May 2023 07:07:26 -0500 Subject: [PATCH 21/34] add comment --- cl/merkle_tree/merkle_root.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cl/merkle_tree/merkle_root.go b/cl/merkle_tree/merkle_root.go index 0a844ac3e88..d115829e949 100644 --- a/cl/merkle_tree/merkle_root.go +++ b/cl/merkle_tree/merkle_root.go @@ -8,6 +8,7 @@ import ( "github.com/prysmaticlabs/gohashtree" ) +// HashByteSlice is gohashtree HashBytSlice but using our hopefully safer header converstion func HashByteSlice(out, in []byte) error { if len(in) == 0 { return errors.New("zero leaves provided") From 0b088233746ea70835ced3661ac3c1246c7cfb19 Mon Sep 17 00:00:00 2001 From: a Date: Wed, 10 May 2023 07:40:48 -0500 Subject: [PATCH 22/34] instrumentation basic --- cmd/erigon-cl/core/state/ssz.go | 19 +++++++++-- .../core/transition/block_transition.go | 18 ++++++++++ metrics/methelp/timer.go | 33 +++++++++++++++++++ 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 metrics/methelp/timer.go diff --git a/cmd/erigon-cl/core/state/ssz.go b/cmd/erigon-cl/core/state/ssz.go index ca26fb33c68..335d4e9200f 100644 --- a/cmd/erigon-cl/core/state/ssz.go +++ b/cmd/erigon-cl/core/state/ssz.go @@ -1,23 +1,38 @@ package state import ( + "github.com/VictoriaMetrics/metrics" "github.com/ledgerwatch/erigon/cl/cltypes/clonable" + "github.com/ledgerwatch/erigon/metrics/methelp" ) func (b *BeaconState) EncodeSSZ(buf []byte) ([]byte, error) { - return b.BeaconState.EncodeSSZ(buf) + h := methelp.NewHistTimer("encode_ssz_beacon_state_dur") + bts, err := b.BeaconState.EncodeSSZ(buf) + if err != nil { + return nil, err + } + h.PutSince() + sz := metrics.NewHistogram("encode_ssz_beacon_state_size") + sz.Update(float64(len(bts))) + return bts, err } func (b *BeaconState) DecodeSSZ(buf []byte, version int) error { + h := methelp.NewHistTimer("decode_ssz_beacon_state_dur") if err := b.BeaconState.DecodeSSZ(buf, version); err != nil { return err } + sz := metrics.NewHistogram("decode_ssz_beacon_state_size") + sz.Update(float64(len(buf))) + h.PutSince() return b.initBeaconState() } // SSZ size of the Beacon State func (b *BeaconState) EncodingSizeSSZ() (size int) { - return b.BeaconState.EncodingSizeSSZ() + sz := b.BeaconState.EncodingSizeSSZ() + return sz } func (b *BeaconState) Clone() clonable.Clonable { diff --git a/cmd/erigon-cl/core/transition/block_transition.go b/cmd/erigon-cl/core/transition/block_transition.go index a3ba1c0fa73..a8b49a936db 100644 --- a/cmd/erigon-cl/core/transition/block_transition.go +++ b/cmd/erigon-cl/core/transition/block_transition.go @@ -8,6 +8,7 @@ import ( "github.com/ledgerwatch/erigon/cl/clparams" "github.com/ledgerwatch/erigon/cl/cltypes" "github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state" + "github.com/ledgerwatch/erigon/metrics/methelp" ) // processBlock takes a block and transitions the state to the next slot, using the provided execution payload if enabled. @@ -19,48 +20,65 @@ func processBlock(state *state.BeaconState, signedBlock *cltypes.SignedBeaconBlo return fmt.Errorf("processBlock: wrong state version for block at slot %d", block.Slot) } + h := methelp.NewHistTimer("beacon_process_block") + + c := h.Child("block_header_dur") // Process the block header. if err := ProcessBlockHeader(state, block, fullValidation); err != nil { return fmt.Errorf("processBlock: failed to process block header: %v", err) } + c.PutSince() // Process execution payload if enabled. if version >= clparams.BellatrixVersion && executionEnabled(state, block.Body.ExecutionPayload) { if state.Version() >= clparams.CapellaVersion { // Process withdrawals in the execution payload. + c = h.Child("withdrawals") if err := ProcessWithdrawals(state, block.Body.ExecutionPayload.Withdrawals, fullValidation); err != nil { return fmt.Errorf("processBlock: failed to process withdrawals: %v", err) } + c.PutSince() } // Process the execution payload. + c = h.Child("execution_payload") if err := ProcessExecutionPayload(state, block.Body.ExecutionPayload); err != nil { return fmt.Errorf("processBlock: failed to process execution payload: %v", err) } + c.PutSince() } // Process RANDAO reveal. + c = h.Child("randao_reveal") if err := ProcessRandao(state, block.Body.RandaoReveal, block.ProposerIndex, fullValidation); err != nil { return fmt.Errorf("processBlock: failed to process RANDAO reveal: %v", err) } + c.PutSince() // Process Eth1 data. + c = h.Child("eth1_data") if err := ProcessEth1Data(state, block.Body.Eth1Data); err != nil { return fmt.Errorf("processBlock: failed to process Eth1 data: %v", err) } + c.PutSince() // Process block body operations. + c = h.Child("operations") if err := processOperations(state, block.Body, fullValidation); err != nil { return fmt.Errorf("processBlock: failed to process block body operations: %v", err) } + c.PutSince() // Process sync aggregate in case of Altair version. if version >= clparams.AltairVersion { + c = h.Child("sync_aggregate") if err := ProcessSyncAggregate(state, block.Body.SyncAggregate, fullValidation); err != nil { return fmt.Errorf("processBlock: failed to process sync aggregate: %v", err) } + c.PutSince() } + h.PutSince() return nil } diff --git a/metrics/methelp/timer.go b/metrics/methelp/timer.go new file mode 100644 index 00000000000..1726c1881c6 --- /dev/null +++ b/metrics/methelp/timer.go @@ -0,0 +1,33 @@ +package methelp + +import ( + "strings" + "time" + + "github.com/VictoriaMetrics/metrics" +) + +type HistTimer struct { + *metrics.Histogram + + start time.Time + + name string +} + +func NewHistTimer(name string) *HistTimer { + return &HistTimer{ + Histogram: metrics.NewHistogram(name), + start: time.Now(), + name: name, + } +} + +func (h *HistTimer) PutSince() { + h.Histogram.UpdateDuration(h.start) +} + +func (h *HistTimer) Child(suffix string) *HistTimer { + suffix = strings.TrimPrefix(suffix, "_") + return NewHistTimer(h.name + "_" + suffix) +} From 6bb3303cc106dacea081f769af23868bcb47be66 Mon Sep 17 00:00:00 2001 From: a Date: Wed, 10 May 2023 09:01:22 -0500 Subject: [PATCH 23/34] basic instrumentation --- cmd/erigon-cl/core/state/ssz.go | 2 +- .../core/transition/block_transition.go | 31 ++++++++++++++----- go.mod | 2 ++ go.sum | 6 ++-- metrics/methelp/timer.go | 11 ++++++- 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/cmd/erigon-cl/core/state/ssz.go b/cmd/erigon-cl/core/state/ssz.go index 335d4e9200f..5774986e278 100644 --- a/cmd/erigon-cl/core/state/ssz.go +++ b/cmd/erigon-cl/core/state/ssz.go @@ -23,7 +23,7 @@ func (b *BeaconState) DecodeSSZ(buf []byte, version int) error { if err := b.BeaconState.DecodeSSZ(buf, version); err != nil { return err } - sz := metrics.NewHistogram("decode_ssz_beacon_state_size") + sz := methelp.NewHistTimer("decode_ssz_beacon_state_size") sz.Update(float64(len(buf))) h.PutSince() return b.initBeaconState() diff --git a/cmd/erigon-cl/core/transition/block_transition.go b/cmd/erigon-cl/core/transition/block_transition.go index a8b49a936db..69b9317aa11 100644 --- a/cmd/erigon-cl/core/transition/block_transition.go +++ b/cmd/erigon-cl/core/transition/block_transition.go @@ -22,7 +22,7 @@ func processBlock(state *state.BeaconState, signedBlock *cltypes.SignedBeaconBlo h := methelp.NewHistTimer("beacon_process_block") - c := h.Child("block_header_dur") + c := h.Tag("process_step", "block_header") // Process the block header. if err := ProcessBlockHeader(state, block, fullValidation); err != nil { return fmt.Errorf("processBlock: failed to process block header: %v", err) @@ -33,7 +33,7 @@ func processBlock(state *state.BeaconState, signedBlock *cltypes.SignedBeaconBlo if version >= clparams.BellatrixVersion && executionEnabled(state, block.Body.ExecutionPayload) { if state.Version() >= clparams.CapellaVersion { // Process withdrawals in the execution payload. - c = h.Child("withdrawals") + c = h.Tag("process_step", "withdrawals") if err := ProcessWithdrawals(state, block.Body.ExecutionPayload.Withdrawals, fullValidation); err != nil { return fmt.Errorf("processBlock: failed to process withdrawals: %v", err) } @@ -41,7 +41,7 @@ func processBlock(state *state.BeaconState, signedBlock *cltypes.SignedBeaconBlo } // Process the execution payload. - c = h.Child("execution_payload") + c = h.Tag("process_step", "execution_payload") if err := ProcessExecutionPayload(state, block.Body.ExecutionPayload); err != nil { return fmt.Errorf("processBlock: failed to process execution payload: %v", err) } @@ -49,21 +49,21 @@ func processBlock(state *state.BeaconState, signedBlock *cltypes.SignedBeaconBlo } // Process RANDAO reveal. - c = h.Child("randao_reveal") + c = h.Tag("process_step", "randao_reveal") if err := ProcessRandao(state, block.Body.RandaoReveal, block.ProposerIndex, fullValidation); err != nil { return fmt.Errorf("processBlock: failed to process RANDAO reveal: %v", err) } c.PutSince() // Process Eth1 data. - c = h.Child("eth1_data") + c = h.Tag("process_step", "eth1_data") if err := ProcessEth1Data(state, block.Body.Eth1Data); err != nil { return fmt.Errorf("processBlock: failed to process Eth1 data: %v", err) } c.PutSince() // Process block body operations. - c = h.Child("operations") + c = h.Tag("process_step", "operations") if err := processOperations(state, block.Body, fullValidation); err != nil { return fmt.Errorf("processBlock: failed to process block body operations: %v", err) } @@ -71,7 +71,7 @@ func processBlock(state *state.BeaconState, signedBlock *cltypes.SignedBeaconBlo // Process sync aggregate in case of Altair version. if version >= clparams.AltairVersion { - c = h.Child("sync_aggregate") + c = h.Tag("process_step", "sync_aggregate") if err := ProcessSyncAggregate(state, block.Body.SyncAggregate, fullValidation); err != nil { return fmt.Errorf("processBlock: failed to process sync aggregate: %v", err) } @@ -86,41 +86,58 @@ func processOperations(state *state.BeaconState, blockBody *cltypes.BeaconBody, if len(blockBody.Deposits) != int(maximumDeposits(state)) { return errors.New("outstanding deposits do not match maximum deposits") } + h := methelp.NewHistTimer("beacon_process_block_operations") + // Process each proposer slashing + c := h.Tag("operation", "proposer_slashings") for _, slashing := range blockBody.ProposerSlashings { if err := ProcessProposerSlashing(state, slashing); err != nil { return fmt.Errorf("ProcessProposerSlashing: %s", err) } } + c.PutSince() // Process each attester slashing + c = h.Tag("operation", "attester_slashings") for _, slashing := range blockBody.AttesterSlashings { if err := ProcessAttesterSlashing(state, slashing); err != nil { return fmt.Errorf("ProcessAttesterSlashing: %s", err) } } + c.PutSince() + // Process each attestations + c = h.Tag("operation", "attestations") if err := ProcessAttestations(state, blockBody.Attestations, fullValidation); err != nil { return fmt.Errorf("ProcessAttestation: %s", err) } + c.PutSince() + // Process each deposit + c = h.Tag("operation", "deposit") for _, dep := range blockBody.Deposits { if err := ProcessDeposit(state, dep, fullValidation); err != nil { return fmt.Errorf("ProcessDeposit: %s", err) } } + c.PutSince() + // Process each voluntary exit. + c = h.Tag("operation", "voluntary_exit") for _, exit := range blockBody.VoluntaryExits { if err := ProcessVoluntaryExit(state, exit, fullValidation); err != nil { return fmt.Errorf("ProcessVoluntaryExit: %s", err) } } + c.PutSince() // Process each execution change. this will only have entries after the capella fork. + c = h.Tag("operation", "execution_change") for _, addressChange := range blockBody.ExecutionChanges { if err := ProcessBlsToExecutionChange(state, addressChange, fullValidation); err != nil { return err } } + c.PutSince() return nil } diff --git a/go.mod b/go.mod index 96853e29efa..08300b12a13 100644 --- a/go.mod +++ b/go.mod @@ -271,3 +271,5 @@ require ( ) replace github.com/tendermint/tendermint => github.com/bnb-chain/tendermint v0.31.12 + +replace github.com/VictoriaMetrics/metrics => github.com/greyireland/metrics v0.0.5 diff --git a/go.sum b/go.sum index 354282685d9..4e3f970e62c 100644 --- a/go.sum +++ b/go.sum @@ -29,8 +29,6 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= -github.com/VictoriaMetrics/metrics v1.23.1 h1:/j8DzeJBxSpL2qSIdqnRFLvQQhbJyJbbEi22yMm7oL0= -github.com/VictoriaMetrics/metrics v1.23.1/go.mod h1:rAr/llLpEnAdTehiNlUxKgnjcOuROSzpw0GvjpEbvFc= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= @@ -358,6 +356,8 @@ github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/greyireland/metrics v0.0.5 h1:FgHLl8lF4D0i77NlgJM7txwdwGStSH5x/thxv2o0IPA= +github.com/greyireland/metrics v0.0.5/go.mod h1:rAr/llLpEnAdTehiNlUxKgnjcOuROSzpw0GvjpEbvFc= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= @@ -681,8 +681,6 @@ github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 h1:0tVE4 github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7/go.mod h1:wmuf/mdK4VMD+jA9ThwcUKjg3a2XWM9cVfFYjDyY4j4= github.com/prysmaticlabs/gohashtree v0.0.3-alpha h1:1EVinCWdb3Lorq7xn8DYQHf48nCcdAM3Vb18KsFlRWY= github.com/prysmaticlabs/gohashtree v0.0.3-alpha/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk= -github.com/prysmaticlabs/gohashtree v0.0.3-alpha.0.20230502123415-aafd8b3ca202 h1:ZsFouPKy81vvQo/Zup5gASVdOm6aiuwUhp7GxvQmjIA= -github.com/prysmaticlabs/gohashtree v0.0.3-alpha.0.20230502123415-aafd8b3ca202/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk= github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE= github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= diff --git a/metrics/methelp/timer.go b/metrics/methelp/timer.go index 1726c1881c6..9450a696ac2 100644 --- a/metrics/methelp/timer.go +++ b/metrics/methelp/timer.go @@ -1,6 +1,7 @@ package methelp import ( + "fmt" "strings" "time" @@ -17,7 +18,7 @@ type HistTimer struct { func NewHistTimer(name string) *HistTimer { return &HistTimer{ - Histogram: metrics.NewHistogram(name), + Histogram: metrics.GetOrCreateCompatibleHistogram(name), start: time.Now(), name: name, } @@ -27,6 +28,14 @@ func (h *HistTimer) PutSince() { h.Histogram.UpdateDuration(h.start) } +func (h *HistTimer) Tag(tag string, value string) *HistTimer { + return &HistTimer{ + Histogram: metrics.GetOrCreateCompatibleHistogram(fmt.Sprintf(`%s{%s="%s"}`, h.name, tag, value)), + start: time.Now(), + name: h.name, + } +} + func (h *HistTimer) Child(suffix string) *HistTimer { suffix = strings.TrimPrefix(suffix, "_") return NewHistTimer(h.name + "_" + suffix) From 811a7f189b1e474db64d83952cea8ea00fc6c14d Mon Sep 17 00:00:00 2001 From: a Date: Wed, 10 May 2023 09:14:41 -0500 Subject: [PATCH 24/34] multiple tags --- metrics/methelp/timer.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/metrics/methelp/timer.go b/metrics/methelp/timer.go index 9450a696ac2..0ccd6a69f5f 100644 --- a/metrics/methelp/timer.go +++ b/metrics/methelp/timer.go @@ -28,9 +28,20 @@ func (h *HistTimer) PutSince() { h.Histogram.UpdateDuration(h.start) } -func (h *HistTimer) Tag(tag string, value string) *HistTimer { +func (h *HistTimer) Tag(pairs ...string) *HistTimer { + if len(pairs)%2 != 0 { + pairs = append(pairs, "UNEQUAL_KEY_VALUE_TAGS") + } + toJoin := []string{} + for i := 0; i < len(pairs); i = i + 2 { + toJoin = append(toJoin, fmt.Sprintf(`%s="%s"`, pairs[i], pairs[i+1])) + } + tags := "" + if len(toJoin) > 0 { + tags = "{" + strings.Join(toJoin, ",") + "}" + } return &HistTimer{ - Histogram: metrics.GetOrCreateCompatibleHistogram(fmt.Sprintf(`%s{%s="%s"}`, h.name, tag, value)), + Histogram: metrics.GetOrCreateCompatibleHistogram(h.name + tags), start: time.Now(), name: h.name, } From aff2bac2f086af95139b58b94bdd0bc7e88d5a5d Mon Sep 17 00:00:00 2001 From: a Date: Wed, 10 May 2023 09:15:46 -0500 Subject: [PATCH 25/34] rawName in timer allows using tag on tag and child on tag --- metrics/methelp/timer.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/metrics/methelp/timer.go b/metrics/methelp/timer.go index 0ccd6a69f5f..3aefda89d1b 100644 --- a/metrics/methelp/timer.go +++ b/metrics/methelp/timer.go @@ -17,10 +17,11 @@ type HistTimer struct { } func NewHistTimer(name string) *HistTimer { + rawName := strings.Split(name, "{") return &HistTimer{ Histogram: metrics.GetOrCreateCompatibleHistogram(name), start: time.Now(), - name: name, + name: rawName[0], } } From 23a727bae365d7230aea886395716a181ec1723a Mon Sep 17 00:00:00 2001 From: a Date: Wed, 10 May 2023 09:23:53 -0500 Subject: [PATCH 26/34] refmt --- cmd/sentinel/sentinel/service/start.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmd/sentinel/sentinel/service/start.go b/cmd/sentinel/sentinel/service/start.go index 23d3628c601..f306fb73c7c 100644 --- a/cmd/sentinel/sentinel/service/start.go +++ b/cmd/sentinel/sentinel/service/start.go @@ -89,7 +89,11 @@ WaitingLoop: } } - conn, err := grpc.DialContext(ctx, srvCfg.Addr, grpc.WithTransportCredentials(creds), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMessageSize))) + conn, err := grpc.DialContext(ctx, + srvCfg.Addr, + grpc.WithTransportCredentials(creds), + grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMessageSize)), + ) if err != nil { return nil, err } From 5cdf994dfda44d4713154d87d0e1aef49fcaafb1 Mon Sep 17 00:00:00 2001 From: a Date: Wed, 10 May 2023 09:34:47 -0500 Subject: [PATCH 27/34] new --- cmd/sentinel/sentinel/sentinel.go | 21 ++++----------------- metrics/exp/exp.go | 11 +++++++---- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/cmd/sentinel/sentinel/sentinel.go b/cmd/sentinel/sentinel/sentinel.go index 4b042a7cfb2..e79f29a6cd3 100644 --- a/cmd/sentinel/sentinel/sentinel.go +++ b/cmd/sentinel/sentinel/sentinel.go @@ -20,7 +20,6 @@ import ( "math" "net" - "net/http" "time" "github.com/ledgerwatch/erigon-lib/kv" @@ -41,7 +40,6 @@ import ( rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" rcmgrObs "github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs" "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" ) const ( @@ -236,10 +234,10 @@ func New( db kv.RoDB, ) (*Sentinel, error) { s := &Sentinel{ - ctx: ctx, - cfg: cfg, - db: db, - // metrics: true, + ctx: ctx, + cfg: cfg, + db: db, + metrics: true, } // Setup discovery @@ -265,17 +263,6 @@ func New( return nil, err } if s.metrics { - http.Handle("/metrics", promhttp.Handler()) - go func() { - server := &http.Server{ - Addr: ":2112", - ReadHeaderTimeout: time.Hour, - } - if err := server.ListenAndServe(); err != nil { - panic(err) - } - }() - rcmgrObs.MustRegisterWith(prometheus.DefaultRegisterer) str, err := rcmgrObs.NewStatsTraceReporter() diff --git a/metrics/exp/exp.go b/metrics/exp/exp.go index 763dc41efe5..76e6ddc76c5 100644 --- a/metrics/exp/exp.go +++ b/metrics/exp/exp.go @@ -8,6 +8,8 @@ import ( metrics2 "github.com/VictoriaMetrics/metrics" "github.com/ledgerwatch/log/v3" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" ) // Setup starts a dedicated metrics server at the given address. @@ -18,10 +20,11 @@ func Setup(address string) { metrics2.WritePrometheus(w, true) }) //m.Handle("/debug/metrics", ExpHandler(metrics.DefaultRegistry)) - //m.Handle("/debug/metrics/prometheus2", promhttp.HandlerFor(prometheus2.DefaultGatherer, promhttp.HandlerOpts{ - // EnableOpenMetrics: true, - //})) - log.Info("Starting metrics server", "addr", fmt.Sprintf("http://%s/debug/metrics/prometheus", address)) + http.Handle("/debug/metrics/prometheus2", promhttp.HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{})) + log.Info("Starting metrics server", "addr", + fmt.Sprintf("http://%s/debug/metrics/prometheus", address), + fmt.Sprintf("http://%s/debug/metrics/prometheus2", address), + ) go func() { if err := http.ListenAndServe(address, nil); err != nil { // nolint:gosec log.Error("Failure in running metrics server", "err", err) From 249a5d46a904e1bb8f8f26831210f059efc774ee Mon Sep 17 00:00:00 2001 From: a Date: Wed, 10 May 2023 10:05:42 -0500 Subject: [PATCH 28/34] combine metric handlers --- cmd/erigon-cl/core/state/cache.go | 8 ++--- cmd/erigon-cl/core/state/cache_accessors.go | 1 + cmd/erigon-cl/core/state/lru/lru.go | 33 +++++++++++++++++++ cmd/erigon-cl/core/state/util.go | 5 +-- .../core/transition/process_attestations.go | 7 +++- metrics/exp/exp.go | 16 ++++++--- 6 files changed, 57 insertions(+), 13 deletions(-) create mode 100644 cmd/erigon-cl/core/state/lru/lru.go diff --git a/cmd/erigon-cl/core/state/cache.go b/cmd/erigon-cl/core/state/cache.go index b7d8f0fe5e0..583b410206f 100644 --- a/cmd/erigon-cl/core/state/cache.go +++ b/cmd/erigon-cl/core/state/cache.go @@ -4,12 +4,12 @@ import ( "crypto/sha256" "encoding/binary" - lru "github.com/hashicorp/golang-lru/v2" "github.com/ledgerwatch/erigon-lib/common" libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon/cl/clparams" "github.com/ledgerwatch/erigon/cl/cltypes" "github.com/ledgerwatch/erigon/cl/utils" + "github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state/lru" "github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state/raw" "github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state/shuffling" ) @@ -194,13 +194,13 @@ func (b *BeaconState) _refreshActiveBalances() { func (b *BeaconState) initCaches() error { var err error - if b.activeValidatorsCache, err = lru.New[uint64, []uint64](5); err != nil { + if b.activeValidatorsCache, err = lru.New[uint64, []uint64]("beacon_active_validators_cache", 5); err != nil { return err } - if b.shuffledSetsCache, err = lru.New[common.Hash, []uint64](5); err != nil { + if b.shuffledSetsCache, err = lru.New[common.Hash, []uint64]("beacon_shuffled_sets_cache", 5); err != nil { return err } - if b.committeeCache, err = lru.New[[16]byte, []uint64](256); err != nil { + if b.committeeCache, err = lru.New[[16]byte, []uint64]("beacon_committee_cache", 256); err != nil { return err } return nil diff --git a/cmd/erigon-cl/core/state/cache_accessors.go b/cmd/erigon-cl/core/state/cache_accessors.go index caf0ea8e872..de4e3c2dc18 100644 --- a/cmd/erigon-cl/core/state/cache_accessors.go +++ b/cmd/erigon-cl/core/state/cache_accessors.go @@ -159,6 +159,7 @@ func (b *BeaconState) GetBeaconCommitee(slot, committeeIndex uint64) ([]uint64, var cacheKey [16]byte binary.BigEndian.PutUint64(cacheKey[:], slot) binary.BigEndian.PutUint64(cacheKey[8:], committeeIndex) + if cachedCommittee, ok := b.committeeCache.Get(cacheKey); ok { return cachedCommittee, nil } diff --git a/cmd/erigon-cl/core/state/lru/lru.go b/cmd/erigon-cl/core/state/lru/lru.go new file mode 100644 index 00000000000..ed7a1f8d2ed --- /dev/null +++ b/cmd/erigon-cl/core/state/lru/lru.go @@ -0,0 +1,33 @@ +package lru + +import ( + "fmt" + + "github.com/VictoriaMetrics/metrics" + lru "github.com/hashicorp/golang-lru/v2" +) + +// Cache is a wrapper around hashicorp lru but with metric for Get +type Cache[K comparable, V any] struct { + *lru.Cache[K, V] + + metricName string +} + +func New[K comparable, V any](metricName string, size int) (*Cache[K, V], error) { + v, err := lru.NewWithEvict[K, V](size, nil) + if err != nil { + return nil, err + } + return &Cache[K, V]{Cache: v, metricName: metricName}, nil +} + +func (c *Cache[K, V]) Get(k K) (V, bool) { + v, ok := c.Cache.Get(k) + if ok { + metrics.GetOrCreateCounter(fmt.Sprintf(`golang_lru_cache_hit{%s="%s"}`, "cache", c.metricName)).Inc() + } else { + metrics.GetOrCreateCounter(fmt.Sprintf(`golang_lru_cache_miss{%s="%s"}`, "cache", c.metricName)).Inc() + } + return v, ok +} diff --git a/cmd/erigon-cl/core/state/util.go b/cmd/erigon-cl/core/state/util.go index f88a1df61c6..e37b456100d 100644 --- a/cmd/erigon-cl/core/state/util.go +++ b/cmd/erigon-cl/core/state/util.go @@ -3,16 +3,13 @@ package state import ( "sort" - lru "github.com/hashicorp/golang-lru/v2" "github.com/ledgerwatch/erigon/cl/clparams" "github.com/ledgerwatch/erigon/cl/cltypes" "github.com/ledgerwatch/erigon/cl/utils" + "github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state/lru" ) func copyLRU[K comparable, V any](dst *lru.Cache[K, V], src *lru.Cache[K, V]) *lru.Cache[K, V] { - if dst == nil { - dst = new(lru.Cache[K, V]) - } dst.Purge() for _, key := range src.Keys() { val, has := src.Get(key) diff --git a/cmd/erigon-cl/core/transition/process_attestations.go b/cmd/erigon-cl/core/transition/process_attestations.go index 8cd27e13c11..97f0cbc76bf 100644 --- a/cmd/erigon-cl/core/transition/process_attestations.go +++ b/cmd/erigon-cl/core/transition/process_attestations.go @@ -8,21 +8,25 @@ import ( "github.com/ledgerwatch/erigon/cl/cltypes" "github.com/ledgerwatch/erigon/cl/utils" "github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state" + "github.com/ledgerwatch/erigon/metrics/methelp" "golang.org/x/exp/slices" ) func ProcessAttestations(s *state.BeaconState, attestations []*cltypes.Attestation, fullValidation bool) error { var err error attestingIndiciesSet := make([][]uint64, len(attestations)) - + h := methelp.NewHistTimer("beacon_process_attestations") baseRewardPerIncrement := s.BaseRewardPerIncrement() + c := h.Tag("attestation_step", "process") for i, attestation := range attestations { if attestingIndiciesSet[i], err = processAttestation(s, attestation, baseRewardPerIncrement); err != nil { return err } } + c.PutSince() if fullValidation { + c = h.Tag("attestation_step", "validate") valid, err := verifyAttestations(s, attestations, attestingIndiciesSet) if err != nil { return err @@ -30,6 +34,7 @@ func ProcessAttestations(s *state.BeaconState, attestations []*cltypes.Attestati if !valid { return errors.New("ProcessAttestation: wrong bls data") } + c.PutSince() } return nil diff --git a/metrics/exp/exp.go b/metrics/exp/exp.go index 76e6ddc76c5..e4e5dbc0c3f 100644 --- a/metrics/exp/exp.go +++ b/metrics/exp/exp.go @@ -9,7 +9,7 @@ import ( metrics2 "github.com/VictoriaMetrics/metrics" "github.com/ledgerwatch/log/v3" "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/prometheus/common/expfmt" ) // Setup starts a dedicated metrics server at the given address. @@ -17,13 +17,21 @@ import ( func Setup(address string) { http.HandleFunc("/debug/metrics/prometheus", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") - metrics2.WritePrometheus(w, true) + metrics2.WritePrometheus(w, false) + contentType := expfmt.Negotiate(r.Header) + enc := expfmt.NewEncoder(w, contentType) + mf, err := prometheus.DefaultGatherer.Gather() + if err != nil { + return + } + for _, m := range mf { + enc.Encode(m) + } }) //m.Handle("/debug/metrics", ExpHandler(metrics.DefaultRegistry)) - http.Handle("/debug/metrics/prometheus2", promhttp.HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{})) + //http.Handle("/debug/metrics/prometheus2", promhttp.HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{})) log.Info("Starting metrics server", "addr", fmt.Sprintf("http://%s/debug/metrics/prometheus", address), - fmt.Sprintf("http://%s/debug/metrics/prometheus2", address), ) go func() { if err := http.ListenAndServe(address, nil); err != nil { // nolint:gosec From d5a42a7cec5dec12b8d04deaeb1b7f5777a51f40 Mon Sep 17 00:00:00 2001 From: a Date: Wed, 10 May 2023 11:35:45 -0500 Subject: [PATCH 29/34] metric --- cmd/erigon-cl/core/transition/block_transition.go | 5 ++++- cmd/erigon-cl/core/transition/process_attestations.go | 11 +++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/cmd/erigon-cl/core/transition/block_transition.go b/cmd/erigon-cl/core/transition/block_transition.go index 69b9317aa11..4616c2fa81a 100644 --- a/cmd/erigon-cl/core/transition/block_transition.go +++ b/cmd/erigon-cl/core/transition/block_transition.go @@ -106,7 +106,10 @@ func processOperations(state *state.BeaconState, blockBody *cltypes.BeaconBody, c.PutSince() // Process each attestations - c = h.Tag("operation", "attestations") + c = h.Tag("operation", "attestations", "validation", "false") + if fullValidation { + c = h.Tag("operation", "attestations", "validation", "true") + } if err := ProcessAttestations(state, blockBody.Attestations, fullValidation); err != nil { return fmt.Errorf("ProcessAttestation: %s", err) } diff --git a/cmd/erigon-cl/core/transition/process_attestations.go b/cmd/erigon-cl/core/transition/process_attestations.go index 97f0cbc76bf..294c9802750 100644 --- a/cmd/erigon-cl/core/transition/process_attestations.go +++ b/cmd/erigon-cl/core/transition/process_attestations.go @@ -46,19 +46,27 @@ func processAttestationPostAltair(s *state.BeaconState, attestation *cltypes.Att stateSlot := s.Slot() beaconConfig := s.BeaconConfig() + h := methelp.NewHistTimer("beacon_process_attestation_post_altair") + + c := h.Tag("step", "get_participation_flag") participationFlagsIndicies, err := s.GetAttestationParticipationFlagIndicies(attestation.Data, stateSlot-data.Slot) if err != nil { return nil, err } + c.PutSince() + c = h.Tag("step", "get_attesting_indices") attestingIndicies, err := s.GetAttestingIndicies(attestation.Data, attestation.AggregationBits, true) if err != nil { return nil, err } + c.PutSince() + var proposerRewardNumerator uint64 isCurrentEpoch := data.Target.Epoch == currentEpoch + c = h.Tag("step", "update_attestation") for _, attesterIndex := range attestingIndicies { val, err := s.ValidatorEffectiveBalance(int(attesterIndex)) if err != nil { @@ -75,11 +83,14 @@ func processAttestationPostAltair(s *state.BeaconState, attestation *cltypes.Att proposerRewardNumerator += baseReward * weight } } + c.PutSince() // Reward proposer + c = h.Tag("step", "get_proposer_index") proposer, err := s.GetBeaconProposerIndex() if err != nil { return nil, err } + c.PutSince() proposerRewardDenominator := (beaconConfig.WeightDenominator - beaconConfig.ProposerWeight) * beaconConfig.WeightDenominator / beaconConfig.ProposerWeight reward := proposerRewardNumerator / proposerRewardDenominator return attestingIndicies, state.IncreaseBalance(s.BeaconState, proposer, reward) From 511ea2310cc40bc24a59250e9055c1df5f42da1e Mon Sep 17 00:00:00 2001 From: a Date: Wed, 10 May 2023 14:11:08 -0500 Subject: [PATCH 30/34] better comment --- cl/cltypes/solid/uint64slice_byte.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cl/cltypes/solid/uint64slice_byte.go b/cl/cltypes/solid/uint64slice_byte.go index 37cf7cea6a6..4a066a784e7 100644 --- a/cl/cltypes/solid/uint64slice_byte.go +++ b/cl/cltypes/solid/uint64slice_byte.go @@ -8,9 +8,12 @@ import ( ) type byteBasedUint64Slice struct { + // the bytes that back the slice u []byte + // length of slice l int // len + // cap of slize c int // cap hashBuf From 5d656696189e78ae3522e567766321a9ff3dddec Mon Sep 17 00:00:00 2001 From: a Date: Wed, 10 May 2023 14:16:30 -0500 Subject: [PATCH 31/34] bitlist --- cl/cltypes/solid/bitlist.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cl/cltypes/solid/bitlist.go b/cl/cltypes/solid/bitlist.go index b0cdcdbb025..6c1c588c783 100644 --- a/cl/cltypes/solid/bitlist.go +++ b/cl/cltypes/solid/bitlist.go @@ -6,8 +6,11 @@ import ( ) type bitlist struct { + // the underlying bytes that store the data u []byte + // cap, or max size of the bitlist c int + // current length of the bitlist l int hashBuf From 1144731078b394e930b9e8c2c78f870e31796748 Mon Sep 17 00:00:00 2001 From: a Date: Thu, 11 May 2023 07:20:18 -0500 Subject: [PATCH 32/34] instrumentation --- cmd/sentinel/sentinel/sentinel.go | 2 -- cmd/sentinel/sentinel/service/start.go | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/sentinel/sentinel/sentinel.go b/cmd/sentinel/sentinel/sentinel.go index e79f29a6cd3..d121c0c7b00 100644 --- a/cmd/sentinel/sentinel/sentinel.go +++ b/cmd/sentinel/sentinel/sentinel.go @@ -39,7 +39,6 @@ import ( "github.com/libp2p/go-libp2p/core/peer" rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" rcmgrObs "github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs" - "github.com/prometheus/client_golang/prometheus" ) const ( @@ -263,7 +262,6 @@ func New( return nil, err } if s.metrics { - rcmgrObs.MustRegisterWith(prometheus.DefaultRegisterer) str, err := rcmgrObs.NewStatsTraceReporter() if err != nil { diff --git a/cmd/sentinel/sentinel/service/start.go b/cmd/sentinel/sentinel/service/start.go index f306fb73c7c..9bd02608462 100644 --- a/cmd/sentinel/sentinel/service/start.go +++ b/cmd/sentinel/sentinel/service/start.go @@ -11,6 +11,8 @@ import ( "github.com/ledgerwatch/erigon/cl/cltypes" "github.com/ledgerwatch/erigon/cmd/sentinel/sentinel" "github.com/ledgerwatch/log/v3" + rcmgrObs "github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs" + "github.com/prometheus/client_golang/prometheus" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" @@ -61,11 +63,11 @@ func createSentinel(cfg *sentinel.SentinelConfig, db kv.RoDB) (*sentinel.Sentine func StartSentinelService(cfg *sentinel.SentinelConfig, db kv.RoDB, srvCfg *ServerConfig, creds credentials.TransportCredentials, initialStatus *cltypes.Status) (sentinelrpc.SentinelClient, error) { ctx := context.Background() - sent, err := createSentinel(cfg, db) if err != nil { return nil, err } + rcmgrObs.MustRegisterWith(prometheus.DefaultRegisterer) log.Info("[Sentinel] Sentinel started", "enr", sent.String()) if initialStatus != nil { sent.SetStatus(initialStatus) From a94aa1a5f75456cda89a300467e501dd57401de4 Mon Sep 17 00:00:00 2001 From: a Date: Thu, 11 May 2023 07:29:31 -0500 Subject: [PATCH 33/34] merge --- cmd/erigon-cl/core/state/ssz.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cmd/erigon-cl/core/state/ssz.go b/cmd/erigon-cl/core/state/ssz.go index f7843eb690d..694547eb270 100644 --- a/cmd/erigon-cl/core/state/ssz.go +++ b/cmd/erigon-cl/core/state/ssz.go @@ -1,13 +1,10 @@ package state import ( -<<<<<<< HEAD "github.com/VictoriaMetrics/metrics" - "github.com/ledgerwatch/erigon/cl/cltypes/clonable" "github.com/ledgerwatch/erigon/metrics/methelp" -======= + "github.com/ledgerwatch/erigon-lib/types/clonable" ->>>>>>> devel ) func (b *BeaconState) EncodeSSZ(buf []byte) ([]byte, error) { From c3b2241b43bb5fb8216b723df62bb358108535df Mon Sep 17 00:00:00 2001 From: a Date: Thu, 11 May 2023 07:43:40 -0500 Subject: [PATCH 34/34] use timer --- cmd/erigon-cl/core/state/ssz.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/erigon-cl/core/state/ssz.go b/cmd/erigon-cl/core/state/ssz.go index 694547eb270..521046c48f1 100644 --- a/cmd/erigon-cl/core/state/ssz.go +++ b/cmd/erigon-cl/core/state/ssz.go @@ -1,7 +1,6 @@ package state import ( - "github.com/VictoriaMetrics/metrics" "github.com/ledgerwatch/erigon/metrics/methelp" "github.com/ledgerwatch/erigon-lib/types/clonable" @@ -14,7 +13,7 @@ func (b *BeaconState) EncodeSSZ(buf []byte) ([]byte, error) { return nil, err } h.PutSince() - sz := metrics.NewHistogram("encode_ssz_beacon_state_size") + sz := methelp.NewHistTimer("encode_ssz_beacon_state_size") sz.Update(float64(len(bts))) return bts, err }