forked from erigontech/erigon
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added checkpoints and justification bits processing (post-altair) (er…
…igontech#6699) * Added processing of checkpoints * Unit tests rigorously imported from prysm * They all pass :)
- Loading branch information
1 parent
20a865b
commit ff21ef7
Showing
17 changed files
with
451 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package cltypes | ||
|
||
import "github.com/ledgerwatch/erigon/cl/utils" | ||
|
||
const JustificationBitsLength = 4 | ||
|
||
type JustificationBits [JustificationBitsLength]bool // Bit vector of size 4 | ||
|
||
func (j JustificationBits) Byte() (out byte) { | ||
for i, bit := range j { | ||
if !bit { | ||
continue | ||
} | ||
out += byte(utils.PowerOf2(uint64(i))) | ||
} | ||
return | ||
} | ||
|
||
func (j *JustificationBits) FromByte(b byte) { | ||
j[0] = b&1 > 0 | ||
j[1] = b&2 > 0 | ||
j[2] = b&4 > 0 | ||
j[3] = b&8 > 0 | ||
} | ||
|
||
// CheckRange checks if bits in certain range are all enabled. | ||
func (j JustificationBits) CheckRange(start int, end int) bool { | ||
checkBits := j[start:end] | ||
for _, bit := range checkBits { | ||
if !bit { | ||
return false | ||
} | ||
} | ||
return true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package cltypes_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/ledgerwatch/erigon/cl/cltypes" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestParticipationBits(t *testing.T) { | ||
bits := cltypes.JustificationBits{} | ||
bits.FromByte(2) | ||
require.Equal(t, bits, cltypes.JustificationBits{false, true, false, false}) | ||
require.Equal(t, bits.Byte(), byte(2)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package cltypes | ||
|
||
import ( | ||
"github.com/ledgerwatch/erigon/cl/utils" | ||
) | ||
|
||
type ParticipationFlags byte | ||
|
||
func (f ParticipationFlags) Add(index int) ParticipationFlags { | ||
return f | ParticipationFlags(utils.PowerOf2(uint64(index))) | ||
} | ||
|
||
func (f ParticipationFlags) HasFlag(index int) bool { | ||
flag := ParticipationFlags(utils.PowerOf2(uint64(index))) | ||
return f&flag == flag | ||
} | ||
|
||
type ParticipationFlagsList []ParticipationFlags | ||
|
||
func (p ParticipationFlagsList) Bytes() []byte { | ||
b := make([]byte, len(p)) | ||
for i := range p { | ||
b[i] = byte(p[i]) | ||
} | ||
return b | ||
} | ||
|
||
func ParticipationFlagsListFromBytes(buf []byte) ParticipationFlagsList { | ||
flagsList := make([]ParticipationFlags, len(buf)) | ||
for i := range flagsList { | ||
flagsList[i] = ParticipationFlags(buf[i]) | ||
} | ||
return flagsList | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package cltypes_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/ledgerwatch/erigon/cl/cltypes" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestParticipationFlags(t *testing.T) { | ||
flagsList := cltypes.ParticipationFlagsListFromBytes([]byte{0, 0, 0, 0}) | ||
flagsList[0] = flagsList[0].Add(4) // Turn on fourth bit | ||
require.True(t, flagsList[0].HasFlag(4)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package state | ||
|
||
import ( | ||
"fmt" | ||
|
||
libcommon "github.com/ledgerwatch/erigon-lib/common" | ||
"github.com/ledgerwatch/erigon/cl/cltypes" | ||
) | ||
|
||
// GetActiveValidatorsIndices returns the list of validator indices active for the given epoch. | ||
func (b *BeaconState) GetActiveValidatorsIndices(epoch uint64) (indicies []uint64) { | ||
for i, validator := range b.validators { | ||
if !validator.Active(epoch) { | ||
continue | ||
} | ||
indicies = append(indicies, uint64(i)) | ||
} | ||
return | ||
} | ||
|
||
// Epoch returns current epoch. | ||
func (b *BeaconState) Epoch() uint64 { | ||
return b.slot / b.beaconConfig.SlotsPerEpoch // Return current state epoch | ||
} | ||
|
||
// PreviousEpoch returns previous epoch. | ||
func (b *BeaconState) PreviousEpoch() uint64 { | ||
epoch := b.Epoch() | ||
if epoch == 0 { | ||
return epoch | ||
} | ||
return epoch - 1 | ||
} | ||
|
||
// getUnslashedParticipatingIndices returns set of currently unslashed participating indexes | ||
func (b *BeaconState) GetUnslashedParticipatingIndices(flagIndex int, epoch uint64) (validatorSet []uint64, err error) { | ||
var participation cltypes.ParticipationFlagsList | ||
// Must be either previous or current epoch | ||
switch epoch { | ||
case b.Epoch(): | ||
participation = b.currentEpochParticipation | ||
case b.PreviousEpoch(): | ||
participation = b.previousEpochParticipation | ||
default: | ||
return nil, fmt.Errorf("getUnslashedParticipatingIndices: only epoch and previous epoch can be used") | ||
} | ||
// Iterate over all validators and include the active ones that have flag_index enabled and are not slashed. | ||
for i, validator := range b.Validators() { | ||
if !validator.Active(epoch) || | ||
!participation[i].HasFlag(flagIndex) || | ||
validator.Slashed { | ||
continue | ||
} | ||
validatorSet = append(validatorSet, uint64(i)) | ||
} | ||
return | ||
} | ||
|
||
// GetTotalBalance return the sum of all balances within the given validator set. | ||
func (b *BeaconState) GetTotalBalance(validatorSet []uint64) (uint64, error) { | ||
var ( | ||
total uint64 | ||
validatorsSize = uint64(len(b.validators)) | ||
) | ||
for _, validatorIndex := range validatorSet { | ||
// Should be in bounds. | ||
if validatorIndex >= validatorsSize { | ||
return 0, fmt.Errorf("GetTotalBalance: out of bounds validator index") | ||
} | ||
total += b.validators[validatorIndex].EffectiveBalance | ||
} | ||
// Always minimum set to EffectiveBalanceIncrement | ||
if total < b.beaconConfig.EffectiveBalanceIncrement { | ||
total = b.beaconConfig.EffectiveBalanceIncrement | ||
} | ||
return total, nil | ||
} | ||
|
||
// GetTotalActiveBalance return the sum of all balances within active validators. | ||
func (b *BeaconState) GetTotalActiveBalance() (uint64, error) { | ||
return b.GetTotalBalance(b.GetActiveValidatorsIndices(b.Epoch())) | ||
} | ||
|
||
// GetBlockRoot returns blook root at start of a given epoch | ||
func (b *BeaconState) GetBlockRoot(epoch uint64) (libcommon.Hash, error) { | ||
return b.GetBlockRootAtSlot(epoch * b.beaconConfig.SlotsPerEpoch) | ||
} | ||
|
||
// GetBlockRootAtSlot returns the block root at a given slot | ||
func (b *BeaconState) GetBlockRootAtSlot(slot uint64) (libcommon.Hash, error) { | ||
if slot >= b.slot { | ||
return libcommon.Hash{}, fmt.Errorf("GetBlockRootAtSlot: slot in the future") | ||
} | ||
if b.slot > slot+b.beaconConfig.SlotsPerHistoricalRoot { | ||
return libcommon.Hash{}, fmt.Errorf("GetBlockRootAtSlot: slot too much far behind") | ||
} | ||
return b.blockRoots[slot%b.beaconConfig.SlotsPerHistoricalRoot], nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package state_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/ledgerwatch/erigon-lib/common" | ||
"github.com/ledgerwatch/erigon/cl/cltypes" | ||
"github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestActiveValidatorIndices(t *testing.T) { | ||
epoch := uint64(2) | ||
testState := state.GetEmptyBeaconState() | ||
// Not Active validator | ||
testState.AddValidator(&cltypes.Validator{ | ||
ActivationEpoch: 3, | ||
ExitEpoch: 9, | ||
EffectiveBalance: 2e9, | ||
}) | ||
// Active Validator | ||
testState.AddValidator(&cltypes.Validator{ | ||
ActivationEpoch: 1, | ||
ExitEpoch: 9, | ||
EffectiveBalance: 2e9, | ||
}) | ||
testState.SetSlot(epoch * 32) // Epoch | ||
testFlags := cltypes.ParticipationFlagsListFromBytes([]byte{1, 1}) | ||
testState.SetCurrentEpochParticipation(testFlags) | ||
// Only validator at index 1 (second validator) is active. | ||
require.Equal(t, testState.GetActiveValidatorsIndices(epoch), []uint64{1}) | ||
set, err := testState.GetUnslashedParticipatingIndices(0x00, epoch) | ||
require.NoError(t, err) | ||
require.Equal(t, set, []uint64{1}) | ||
// Check if balances are retrieved correctly | ||
totalBalance, err := testState.GetTotalActiveBalance() | ||
require.NoError(t, err) | ||
require.Equal(t, totalBalance, uint64(2e9)) | ||
} | ||
|
||
func TestGetBlockRoot(t *testing.T) { | ||
epoch := uint64(2) | ||
testState := state.GetEmptyBeaconState() | ||
root := common.HexToHash("ff") | ||
testState.SetSlot(100) | ||
testState.SetBlockRootAt(int(epoch*32), root) | ||
retrieved, err := testState.GetBlockRoot(epoch) | ||
require.NoError(t, err) | ||
require.Equal(t, retrieved, root) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.