mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-03 08:37:37 +00:00
Unrealized justification (#10659)
* unrealized justification API * Add time elapse logging * add unrealized justification checkpoint * Use UnrealizedJustificationCheckpoint * Refactor unrealized checkpoints * Move logic to state package * do not use ctx on a sum * fix ctx * add tests * fix conflicts * unhandled error * Fix ordering in computing checkpoints * gaz * keep finalized checkpoint if nothing justified * gaz * copy checkpoint * fix check for nil * Add state package tests * Add tests * Radek's review * add more tests * Update beacon-chain/core/epoch/precompute/justification_finalization.go Co-authored-by: terencechain <terence@prysmaticlabs.com> * deduplicate to stateutil * missing file * Add stateutil test * Minor refactor, don't export certain things * Fix exports in tests * remove unused error Co-authored-by: terence tsao <terence@prysmaticlabs.com> Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
parent
adabd1fa4f
commit
3cf385fe91
@ -47,7 +47,7 @@ func InitializePrecomputeValidators(ctx context.Context, beaconState state.Beaco
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Set validator's active status for preivous epoch.
|
// Set validator's active status for previous epoch.
|
||||||
if helpers.IsActiveValidatorUsingTrie(val, prevEpoch) {
|
if helpers.IsActiveValidatorUsingTrie(val, prevEpoch) {
|
||||||
v.IsActivePrevEpoch = true
|
v.IsActivePrevEpoch = true
|
||||||
bal.ActivePrevEpoch, err = math.Add64(bal.ActivePrevEpoch, val.EffectiveBalance())
|
bal.ActivePrevEpoch, err = math.Add64(bal.ActivePrevEpoch, val.EffectiveBalance())
|
||||||
|
@ -28,6 +28,7 @@ go_library(
|
|||||||
"//runtime/version:go_default_library",
|
"//runtime/version:go_default_library",
|
||||||
"//time/slots:go_default_library",
|
"//time/slots:go_default_library",
|
||||||
"@com_github_pkg_errors//:go_default_library",
|
"@com_github_pkg_errors//:go_default_library",
|
||||||
|
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||||
"@io_opencensus_go//trace:go_default_library",
|
"@io_opencensus_go//trace:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@ -43,11 +44,13 @@ go_test(
|
|||||||
],
|
],
|
||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//beacon-chain/core/altair:go_default_library",
|
||||||
"//beacon-chain/core/epoch:go_default_library",
|
"//beacon-chain/core/epoch:go_default_library",
|
||||||
"//beacon-chain/core/helpers:go_default_library",
|
"//beacon-chain/core/helpers:go_default_library",
|
||||||
"//beacon-chain/core/time:go_default_library",
|
"//beacon-chain/core/time:go_default_library",
|
||||||
"//beacon-chain/state:go_default_library",
|
"//beacon-chain/state:go_default_library",
|
||||||
"//beacon-chain/state/v1:go_default_library",
|
"//beacon-chain/state/v1:go_default_library",
|
||||||
|
"//beacon-chain/state/v2:go_default_library",
|
||||||
"//config/fieldparams:go_default_library",
|
"//config/fieldparams:go_default_library",
|
||||||
"//config/params:go_default_library",
|
"//config/params:go_default_library",
|
||||||
"//consensus-types/primitives:go_default_library",
|
"//consensus-types/primitives:go_default_library",
|
||||||
|
@ -2,6 +2,7 @@ package precompute
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/prysmaticlabs/go-bitfield"
|
||||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
|
||||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||||
@ -9,6 +10,24 @@ import (
|
|||||||
"github.com/prysmaticlabs/prysm/time/slots"
|
"github.com/prysmaticlabs/prysm/time/slots"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var errNilState = errors.New("nil state")
|
||||||
|
|
||||||
|
// UnrealizedCheckpoints returns the justification and finalization checkpoints of the
|
||||||
|
// given state as if it was progressed with empty slots until the next epoch.
|
||||||
|
func UnrealizedCheckpoints(st state.BeaconState) (*ethpb.Checkpoint, *ethpb.Checkpoint, error) {
|
||||||
|
if st == nil || st.IsNil() {
|
||||||
|
return nil, nil, errNilState
|
||||||
|
}
|
||||||
|
|
||||||
|
activeBalance, prevTarget, currentTarget, err := st.UnrealizedCheckpointBalances()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
justification := processJustificationBits(st, activeBalance, prevTarget, currentTarget)
|
||||||
|
return computeCheckpoints(st, justification)
|
||||||
|
}
|
||||||
|
|
||||||
// ProcessJustificationAndFinalizationPreCompute processes justification and finalization during
|
// ProcessJustificationAndFinalizationPreCompute processes justification and finalization during
|
||||||
// epoch processing. This is where a beacon node can justify and finalize a new epoch.
|
// epoch processing. This is where a beacon node can justify and finalize a new epoch.
|
||||||
// Note: this is an optimized version by passing in precomputed total and attesting balances.
|
// Note: this is an optimized version by passing in precomputed total and attesting balances.
|
||||||
@ -34,12 +53,55 @@ func ProcessJustificationAndFinalizationPreCompute(state state.BeaconState, pBal
|
|||||||
return state, nil
|
return state, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return weighJustificationAndFinalization(state, pBal.ActiveCurrentEpoch, pBal.PrevEpochTargetAttested, pBal.CurrentEpochTargetAttested)
|
newBits := processJustificationBits(state, pBal.ActiveCurrentEpoch, pBal.PrevEpochTargetAttested, pBal.CurrentEpochTargetAttested)
|
||||||
|
|
||||||
|
return weighJustificationAndFinalization(state, newBits)
|
||||||
}
|
}
|
||||||
|
|
||||||
// weighJustificationAndFinalization processes justification and finalization during
|
// processJustificationBits processes the justification bits during epoch processing.
|
||||||
|
func processJustificationBits(state state.BeaconState, totalActiveBalance, prevEpochTargetBalance, currEpochTargetBalance uint64) bitfield.Bitvector4 {
|
||||||
|
newBits := state.JustificationBits()
|
||||||
|
newBits.Shift(1)
|
||||||
|
// If 2/3 or more of total balance attested in the previous epoch.
|
||||||
|
if 3*prevEpochTargetBalance >= 2*totalActiveBalance {
|
||||||
|
newBits.SetBitAt(1, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 3*currEpochTargetBalance >= 2*totalActiveBalance {
|
||||||
|
newBits.SetBitAt(0, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return newBits
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateJustificationAndFinalization processes justification and finalization during
|
||||||
// epoch processing. This is where a beacon node can justify and finalize a new epoch.
|
// epoch processing. This is where a beacon node can justify and finalize a new epoch.
|
||||||
//
|
func weighJustificationAndFinalization(state state.BeaconState, newBits bitfield.Bitvector4) (state.BeaconState, error) {
|
||||||
|
jc, fc, err := computeCheckpoints(state, newBits)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := state.SetPreviousJustifiedCheckpoint(state.CurrentJustifiedCheckpoint()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := state.SetCurrentJustifiedCheckpoint(jc); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := state.SetJustificationBits(newBits); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := state.SetFinalizedCheckpoint(fc); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return state, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// computeCheckpoints computes the new Justification and Finalization
|
||||||
|
// checkpoints at epoch transition
|
||||||
// Spec pseudocode definition:
|
// Spec pseudocode definition:
|
||||||
// def weigh_justification_and_finalization(state: BeaconState,
|
// def weigh_justification_and_finalization(state: BeaconState,
|
||||||
// total_active_balance: Gwei,
|
// total_active_balance: Gwei,
|
||||||
@ -77,88 +139,57 @@ func ProcessJustificationAndFinalizationPreCompute(state state.BeaconState, pBal
|
|||||||
// # The 1st/2nd most recent epochs are justified, the 1st using the 2nd as source
|
// # The 1st/2nd most recent epochs are justified, the 1st using the 2nd as source
|
||||||
// if all(bits[0:2]) and old_current_justified_checkpoint.epoch + 1 == current_epoch:
|
// if all(bits[0:2]) and old_current_justified_checkpoint.epoch + 1 == current_epoch:
|
||||||
// state.finalized_checkpoint = old_current_justified_checkpoint
|
// state.finalized_checkpoint = old_current_justified_checkpoint
|
||||||
func weighJustificationAndFinalization(state state.BeaconState,
|
func computeCheckpoints(state state.BeaconState, newBits bitfield.Bitvector4) (*ethpb.Checkpoint, *ethpb.Checkpoint, error) {
|
||||||
totalActiveBalance, prevEpochTargetBalance, currEpochTargetBalance uint64) (state.BeaconState, error) {
|
|
||||||
prevEpoch := time.PrevEpoch(state)
|
prevEpoch := time.PrevEpoch(state)
|
||||||
currentEpoch := time.CurrentEpoch(state)
|
currentEpoch := time.CurrentEpoch(state)
|
||||||
oldPrevJustifiedCheckpoint := state.PreviousJustifiedCheckpoint()
|
oldPrevJustifiedCheckpoint := state.PreviousJustifiedCheckpoint()
|
||||||
oldCurrJustifiedCheckpoint := state.CurrentJustifiedCheckpoint()
|
oldCurrJustifiedCheckpoint := state.CurrentJustifiedCheckpoint()
|
||||||
|
|
||||||
// Process justifications
|
justifiedCheckpoint := state.CurrentJustifiedCheckpoint()
|
||||||
if err := state.SetPreviousJustifiedCheckpoint(state.CurrentJustifiedCheckpoint()); err != nil {
|
finalizedCheckpoint := state.FinalizedCheckpoint()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
newBits := state.JustificationBits()
|
|
||||||
newBits.Shift(1)
|
|
||||||
if err := state.SetJustificationBits(newBits); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: the spec refers to the bit index position starting at 1 instead of starting at zero.
|
|
||||||
// We will use that paradigm here for consistency with the godoc spec definition.
|
|
||||||
|
|
||||||
// If 2/3 or more of total balance attested in the previous epoch.
|
|
||||||
if 3*prevEpochTargetBalance >= 2*totalActiveBalance {
|
|
||||||
blockRoot, err := helpers.BlockRoot(state, prevEpoch)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "could not get block root for previous epoch %d", prevEpoch)
|
|
||||||
}
|
|
||||||
if err := state.SetCurrentJustifiedCheckpoint(ðpb.Checkpoint{Epoch: prevEpoch, Root: blockRoot}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
newBits = state.JustificationBits()
|
|
||||||
newBits.SetBitAt(1, true)
|
|
||||||
if err := state.SetJustificationBits(newBits); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If 2/3 or more of the total balance attested in the current epoch.
|
// If 2/3 or more of the total balance attested in the current epoch.
|
||||||
if 3*currEpochTargetBalance >= 2*totalActiveBalance {
|
if newBits.BitAt(0) {
|
||||||
blockRoot, err := helpers.BlockRoot(state, currentEpoch)
|
blockRoot, err := helpers.BlockRoot(state, currentEpoch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "could not get block root for current epoch %d", prevEpoch)
|
return nil, nil, errors.Wrapf(err, "could not get block root for current epoch %d", currentEpoch)
|
||||||
}
|
}
|
||||||
if err := state.SetCurrentJustifiedCheckpoint(ðpb.Checkpoint{Epoch: currentEpoch, Root: blockRoot}); err != nil {
|
justifiedCheckpoint.Epoch = currentEpoch
|
||||||
return nil, err
|
justifiedCheckpoint.Root = blockRoot
|
||||||
}
|
} else if newBits.BitAt(1) {
|
||||||
newBits = state.JustificationBits()
|
// If 2/3 or more of total balance attested in the previous epoch.
|
||||||
newBits.SetBitAt(0, true)
|
blockRoot, err := helpers.BlockRoot(state, prevEpoch)
|
||||||
if err := state.SetJustificationBits(newBits); err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, errors.Wrapf(err, "could not get block root for previous epoch %d", prevEpoch)
|
||||||
}
|
}
|
||||||
|
justifiedCheckpoint.Epoch = prevEpoch
|
||||||
|
justifiedCheckpoint.Root = blockRoot
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process finalization according to Ethereum Beacon Chain specification.
|
// Process finalization according to Ethereum Beacon Chain specification.
|
||||||
justification := state.JustificationBits().Bytes()[0]
|
if len(newBits) == 0 {
|
||||||
|
return nil, nil, errors.New("empty justification bits")
|
||||||
|
}
|
||||||
|
justification := newBits.Bytes()[0]
|
||||||
|
|
||||||
// 2nd/3rd/4th (0b1110) most recent epochs are justified, the 2nd using the 4th as source.
|
// 2nd/3rd/4th (0b1110) most recent epochs are justified, the 2nd using the 4th as source.
|
||||||
if justification&0x0E == 0x0E && (oldPrevJustifiedCheckpoint.Epoch+3) == currentEpoch {
|
if justification&0x0E == 0x0E && (oldPrevJustifiedCheckpoint.Epoch+3) == currentEpoch {
|
||||||
if err := state.SetFinalizedCheckpoint(oldPrevJustifiedCheckpoint); err != nil {
|
finalizedCheckpoint = oldPrevJustifiedCheckpoint
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd/3rd (0b0110) most recent epochs are justified, the 2nd using the 3rd as source.
|
// 2nd/3rd (0b0110) most recent epochs are justified, the 2nd using the 3rd as source.
|
||||||
if justification&0x06 == 0x06 && (oldPrevJustifiedCheckpoint.Epoch+2) == currentEpoch {
|
if justification&0x06 == 0x06 && (oldPrevJustifiedCheckpoint.Epoch+2) == currentEpoch {
|
||||||
if err := state.SetFinalizedCheckpoint(oldPrevJustifiedCheckpoint); err != nil {
|
finalizedCheckpoint = oldPrevJustifiedCheckpoint
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1st/2nd/3rd (0b0111) most recent epochs are justified, the 1st using the 3rd as source.
|
// 1st/2nd/3rd (0b0111) most recent epochs are justified, the 1st using the 3rd as source.
|
||||||
if justification&0x07 == 0x07 && (oldCurrJustifiedCheckpoint.Epoch+2) == currentEpoch {
|
if justification&0x07 == 0x07 && (oldCurrJustifiedCheckpoint.Epoch+2) == currentEpoch {
|
||||||
if err := state.SetFinalizedCheckpoint(oldCurrJustifiedCheckpoint); err != nil {
|
finalizedCheckpoint = oldCurrJustifiedCheckpoint
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The 1st/2nd (0b0011) most recent epochs are justified, the 1st using the 2nd as source
|
// The 1st/2nd (0b0011) most recent epochs are justified, the 1st using the 2nd as source
|
||||||
if justification&0x03 == 0x03 && (oldCurrJustifiedCheckpoint.Epoch+1) == currentEpoch {
|
if justification&0x03 == 0x03 && (oldCurrJustifiedCheckpoint.Epoch+1) == currentEpoch {
|
||||||
if err := state.SetFinalizedCheckpoint(oldCurrJustifiedCheckpoint); err != nil {
|
finalizedCheckpoint = oldCurrJustifiedCheckpoint
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return justifiedCheckpoint, finalizedCheckpoint, nil
|
||||||
return state, nil
|
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
package precompute_test
|
package precompute_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/prysmaticlabs/go-bitfield"
|
"github.com/prysmaticlabs/go-bitfield"
|
||||||
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
|
||||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
|
||||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||||
|
v2 "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||||
"github.com/prysmaticlabs/prysm/config/params"
|
"github.com/prysmaticlabs/prysm/config/params"
|
||||||
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||||
@ -123,3 +126,127 @@ func TestProcessJustificationAndFinalizationPreCompute_JustifyPrevEpoch(t *testi
|
|||||||
assert.DeepEqual(t, params.BeaconConfig().ZeroHash[:], newState.FinalizedCheckpoint().Root)
|
assert.DeepEqual(t, params.BeaconConfig().ZeroHash[:], newState.FinalizedCheckpoint().Root)
|
||||||
assert.Equal(t, types.Epoch(0), newState.FinalizedCheckpointEpoch(), "Unexpected finalized epoch")
|
assert.Equal(t, types.Epoch(0), newState.FinalizedCheckpointEpoch(), "Unexpected finalized epoch")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUnrealizedCheckpoints(t *testing.T) {
|
||||||
|
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||||
|
balances := make([]uint64, len(validators))
|
||||||
|
for i := 0; i < len(validators); i++ {
|
||||||
|
validators[i] = ðpb.Validator{
|
||||||
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||||
|
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||||
|
}
|
||||||
|
balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
||||||
|
}
|
||||||
|
pjr := [32]byte{'p'}
|
||||||
|
cjr := [32]byte{'c'}
|
||||||
|
je := types.Epoch(3)
|
||||||
|
fe := types.Epoch(2)
|
||||||
|
pjcp := ðpb.Checkpoint{Root: pjr[:], Epoch: fe}
|
||||||
|
cjcp := ðpb.Checkpoint{Root: cjr[:], Epoch: je}
|
||||||
|
fcp := ðpb.Checkpoint{Root: pjr[:], Epoch: fe}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
slot types.Slot
|
||||||
|
prevVals, currVals int
|
||||||
|
expectedJustified, expectedFinalized types.Epoch // The expected unrealized checkpoint epochs
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"Not enough votes, keep previous justification",
|
||||||
|
129,
|
||||||
|
len(validators) / 3,
|
||||||
|
len(validators) / 3,
|
||||||
|
je,
|
||||||
|
fe,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Not enough votes, keep previous justification, N+2",
|
||||||
|
161,
|
||||||
|
len(validators) / 3,
|
||||||
|
len(validators) / 3,
|
||||||
|
je,
|
||||||
|
fe,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Enough to justify previous epoch but not current",
|
||||||
|
129,
|
||||||
|
2*len(validators)/3 + 3,
|
||||||
|
len(validators) / 3,
|
||||||
|
je,
|
||||||
|
fe,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Enough to justify previous epoch but not current, N+2",
|
||||||
|
161,
|
||||||
|
2*len(validators)/3 + 3,
|
||||||
|
len(validators) / 3,
|
||||||
|
je + 1,
|
||||||
|
fe,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Enough to justify current epoch",
|
||||||
|
129,
|
||||||
|
len(validators) / 3,
|
||||||
|
2*len(validators)/3 + 3,
|
||||||
|
je + 1,
|
||||||
|
fe,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Enough to justify current epoch, but not previous",
|
||||||
|
161,
|
||||||
|
len(validators) / 3,
|
||||||
|
2*len(validators)/3 + 3,
|
||||||
|
je + 2,
|
||||||
|
fe,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Enough to justify current and previous",
|
||||||
|
161,
|
||||||
|
2*len(validators)/3 + 3,
|
||||||
|
2*len(validators)/3 + 3,
|
||||||
|
je + 2,
|
||||||
|
fe,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
base := ðpb.BeaconStateAltair{
|
||||||
|
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||||
|
|
||||||
|
Validators: validators,
|
||||||
|
Slot: test.slot,
|
||||||
|
CurrentEpochParticipation: make([]byte, params.BeaconConfig().MinGenesisActiveValidatorCount),
|
||||||
|
PreviousEpochParticipation: make([]byte, params.BeaconConfig().MinGenesisActiveValidatorCount),
|
||||||
|
Balances: balances,
|
||||||
|
PreviousJustifiedCheckpoint: pjcp,
|
||||||
|
CurrentJustifiedCheckpoint: cjcp,
|
||||||
|
FinalizedCheckpoint: fcp,
|
||||||
|
InactivityScores: make([]uint64, len(validators)),
|
||||||
|
JustificationBits: make(bitfield.Bitvector4, 1),
|
||||||
|
}
|
||||||
|
for i := 0; i < test.prevVals; i++ {
|
||||||
|
base.PreviousEpochParticipation[i] = 0xFF
|
||||||
|
}
|
||||||
|
for i := 0; i < test.currVals; i++ {
|
||||||
|
base.CurrentEpochParticipation[i] = 0xFF
|
||||||
|
}
|
||||||
|
if test.slot > 130 {
|
||||||
|
base.JustificationBits.SetBitAt(2, true)
|
||||||
|
base.JustificationBits.SetBitAt(3, true)
|
||||||
|
} else {
|
||||||
|
base.JustificationBits.SetBitAt(1, true)
|
||||||
|
base.JustificationBits.SetBitAt(2, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
state, err := v2.InitializeFromProto(base)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, _, err = altair.InitializePrecomputeValidators(context.Background(), state)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
jc, fc, err := precompute.UnrealizedCheckpoints(state)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.DeepEqual(t, test.expectedJustified, jc.Epoch)
|
||||||
|
require.DeepEqual(t, test.expectedFinalized, fc.Epoch)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -223,6 +223,7 @@ type FutureForkStub interface {
|
|||||||
AppendInactivityScore(s uint64) error
|
AppendInactivityScore(s uint64) error
|
||||||
CurrentEpochParticipation() ([]byte, error)
|
CurrentEpochParticipation() ([]byte, error)
|
||||||
PreviousEpochParticipation() ([]byte, error)
|
PreviousEpochParticipation() ([]byte, error)
|
||||||
|
UnrealizedCheckpointBalances() (uint64, uint64, uint64, error)
|
||||||
InactivityScores() ([]uint64, error)
|
InactivityScores() ([]uint64, error)
|
||||||
SetInactivityScores(val []uint64) error
|
SetInactivityScores(val []uint64) error
|
||||||
CurrentSyncCommittee() (*ethpb.SyncCommittee, error)
|
CurrentSyncCommittee() (*ethpb.SyncCommittee, error)
|
||||||
|
@ -4,6 +4,7 @@ go_library(
|
|||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
"doc.go",
|
"doc.go",
|
||||||
|
"error.go",
|
||||||
"getters_attestation.go",
|
"getters_attestation.go",
|
||||||
"getters_block.go",
|
"getters_block.go",
|
||||||
"getters_checkpoint.go",
|
"getters_checkpoint.go",
|
||||||
@ -54,6 +55,7 @@ go_library(
|
|||||||
"//tools/pcli:__pkg__",
|
"//tools/pcli:__pkg__",
|
||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//beacon-chain/core/time:go_default_library",
|
||||||
"//beacon-chain/state:go_default_library",
|
"//beacon-chain/state:go_default_library",
|
||||||
"//beacon-chain/state/fieldtrie:go_default_library",
|
"//beacon-chain/state/fieldtrie:go_default_library",
|
||||||
"//beacon-chain/state/state-native/custom-types:go_default_library",
|
"//beacon-chain/state/state-native/custom-types:go_default_library",
|
||||||
@ -83,6 +85,7 @@ go_test(
|
|||||||
"getters_attestation_test.go",
|
"getters_attestation_test.go",
|
||||||
"getters_block_test.go",
|
"getters_block_test.go",
|
||||||
"getters_checkpoint_test.go",
|
"getters_checkpoint_test.go",
|
||||||
|
"getters_participation_test.go",
|
||||||
"getters_test.go",
|
"getters_test.go",
|
||||||
"getters_validator_test.go",
|
"getters_validator_test.go",
|
||||||
"hasher_test.go",
|
"hasher_test.go",
|
||||||
|
5
beacon-chain/state/state-native/error.go
Normal file
5
beacon-chain/state/state-native/error.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package state_native
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var ErrNilParticipation = errors.New("Nil epoch participation in state")
|
@ -1,6 +1,8 @@
|
|||||||
package state_native
|
package state_native
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
|
||||||
|
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||||
"github.com/prysmaticlabs/prysm/runtime/version"
|
"github.com/prysmaticlabs/prysm/runtime/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,6 +38,28 @@ func (b *BeaconState) PreviousEpochParticipation() ([]byte, error) {
|
|||||||
return b.previousEpochParticipationVal(), nil
|
return b.previousEpochParticipationVal(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnrealizedCheckpointBalances returns the total balances: active, target attested in
|
||||||
|
// current epoch and target attested in previous epoch. This function is used to
|
||||||
|
// compute the "unrealized justification" that a synced Beacon Block will have.
|
||||||
|
func (b *BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, error) {
|
||||||
|
if b.version == version.Phase0 {
|
||||||
|
return 0, 0, 0, errNotSupported("UnrealizedCheckpointBalances", b.version)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.lock.RLock()
|
||||||
|
defer b.lock.RUnlock()
|
||||||
|
|
||||||
|
cp := b.currentEpochParticipation
|
||||||
|
pp := b.previousEpochParticipation
|
||||||
|
if cp == nil || pp == nil {
|
||||||
|
return 0, 0, 0, ErrNilParticipation
|
||||||
|
}
|
||||||
|
|
||||||
|
currentEpoch := time.CurrentEpoch(b)
|
||||||
|
return stateutil.UnrealizedCheckpointBalances(cp, pp, b.validators, currentEpoch)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// currentEpochParticipationVal corresponding to participation bits on the beacon chain.
|
// currentEpochParticipationVal corresponding to participation bits on the beacon chain.
|
||||||
// This assumes that a lock is already held on BeaconState.
|
// This assumes that a lock is already held on BeaconState.
|
||||||
func (b *BeaconState) currentEpochParticipationVal() []byte {
|
func (b *BeaconState) currentEpochParticipationVal() []byte {
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
package state_native
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/prysmaticlabs/prysm/config/params"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||||
|
"github.com/prysmaticlabs/prysm/testing/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestState_UnrealizedCheckpointBalances(t *testing.T) {
|
||||||
|
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||||
|
balances := make([]uint64, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||||
|
for i := 0; i < len(validators); i++ {
|
||||||
|
validators[i] = ðpb.Validator{
|
||||||
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||||
|
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||||
|
}
|
||||||
|
balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
||||||
|
}
|
||||||
|
base := ðpb.BeaconStateAltair{
|
||||||
|
Slot: 2,
|
||||||
|
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||||
|
|
||||||
|
Validators: validators,
|
||||||
|
CurrentEpochParticipation: make([]byte, params.BeaconConfig().MinGenesisActiveValidatorCount),
|
||||||
|
PreviousEpochParticipation: make([]byte, params.BeaconConfig().MinGenesisActiveValidatorCount),
|
||||||
|
Balances: balances,
|
||||||
|
}
|
||||||
|
state, err := InitializeFromProtoAltair(base)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// No one voted in the last two epochs
|
||||||
|
allActive := params.BeaconConfig().MinGenesisActiveValidatorCount * params.BeaconConfig().MaxEffectiveBalance
|
||||||
|
active, previous, current, err := state.UnrealizedCheckpointBalances()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, allActive, active)
|
||||||
|
require.Equal(t, uint64(0), current)
|
||||||
|
require.Equal(t, uint64(0), previous)
|
||||||
|
|
||||||
|
// Add some votes in the last two epochs:
|
||||||
|
base.CurrentEpochParticipation[0] = 0xFF
|
||||||
|
base.PreviousEpochParticipation[0] = 0xFF
|
||||||
|
base.PreviousEpochParticipation[1] = 0xFF
|
||||||
|
|
||||||
|
state, err = InitializeFromProtoAltair(base)
|
||||||
|
require.NoError(t, err)
|
||||||
|
active, previous, current, err = state.UnrealizedCheckpointBalances()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, allActive, active)
|
||||||
|
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, current)
|
||||||
|
require.Equal(t, 2*params.BeaconConfig().MaxEffectiveBalance, previous)
|
||||||
|
|
||||||
|
// Slash some validators
|
||||||
|
validators[0].Slashed = true
|
||||||
|
state, err = InitializeFromProtoAltair(base)
|
||||||
|
require.NoError(t, err)
|
||||||
|
active, previous, current, err = state.UnrealizedCheckpointBalances()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, allActive-params.BeaconConfig().MaxEffectiveBalance, active)
|
||||||
|
require.Equal(t, uint64(0), current)
|
||||||
|
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, previous)
|
||||||
|
|
||||||
|
}
|
@ -15,6 +15,7 @@ go_library(
|
|||||||
"state_hasher.go",
|
"state_hasher.go",
|
||||||
"sync_committee.root.go",
|
"sync_committee.root.go",
|
||||||
"trie_helpers.go",
|
"trie_helpers.go",
|
||||||
|
"unrealized_justification.go",
|
||||||
"validator_map_handler.go",
|
"validator_map_handler.go",
|
||||||
"validator_root.go",
|
"validator_root.go",
|
||||||
],
|
],
|
||||||
@ -57,6 +58,7 @@ go_test(
|
|||||||
"reference_bench_test.go",
|
"reference_bench_test.go",
|
||||||
"state_root_test.go",
|
"state_root_test.go",
|
||||||
"trie_helpers_test.go",
|
"trie_helpers_test.go",
|
||||||
|
"unrealized_justification_test.go",
|
||||||
"validator_root_test.go",
|
"validator_root_test.go",
|
||||||
],
|
],
|
||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
|
43
beacon-chain/state/stateutil/unrealized_justification.go
Normal file
43
beacon-chain/state/stateutil/unrealized_justification.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package stateutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/prysmaticlabs/prysm/config/params"
|
||||||
|
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||||
|
"github.com/prysmaticlabs/prysm/math"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UnrealizedCheckpointBalances(cp, pp []byte, validators []*ethpb.Validator, currentEpoch types.Epoch) (uint64, uint64, uint64, error) {
|
||||||
|
targetIdx := params.BeaconConfig().TimelyTargetFlagIndex
|
||||||
|
activeBalance := uint64(0)
|
||||||
|
currentTarget := uint64(0)
|
||||||
|
prevTarget := uint64(0)
|
||||||
|
if len(cp) < len(validators) || len(pp) < len(validators) {
|
||||||
|
return 0, 0, 0, errors.New("participation does not match validator set")
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
for i, v := range validators {
|
||||||
|
active := v.ActivationEpoch <= currentEpoch && currentEpoch < v.ExitEpoch
|
||||||
|
if active && !v.Slashed {
|
||||||
|
activeBalance, err = math.Add64(activeBalance, v.EffectiveBalance)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, 0, err
|
||||||
|
}
|
||||||
|
if ((cp[i] >> targetIdx) & 1) == 1 {
|
||||||
|
currentTarget, err = math.Add64(currentTarget, v.EffectiveBalance)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((pp[i] >> targetIdx) & 1) == 1 {
|
||||||
|
prevTarget, err = math.Add64(prevTarget, v.EffectiveBalance)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return activeBalance, prevTarget, currentTarget, nil
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
package stateutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/prysmaticlabs/prysm/config/params"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||||
|
"github.com/prysmaticlabs/prysm/testing/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestState_UnrealizedCheckpointBalances(t *testing.T) {
|
||||||
|
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||||
|
targetFlag := params.BeaconConfig().TimelyTargetFlagIndex
|
||||||
|
expectedActive := params.BeaconConfig().MinGenesisActiveValidatorCount * params.BeaconConfig().MaxEffectiveBalance
|
||||||
|
|
||||||
|
balances := make([]uint64, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||||
|
for i := 0; i < len(validators); i++ {
|
||||||
|
validators[i] = ðpb.Validator{
|
||||||
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||||
|
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||||
|
}
|
||||||
|
balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
||||||
|
}
|
||||||
|
cp := make([]byte, len(validators))
|
||||||
|
pp := make([]byte, len(validators))
|
||||||
|
|
||||||
|
t.Run("No one voted last two epochs", func(tt *testing.T) {
|
||||||
|
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, validators, 0)
|
||||||
|
require.NoError(tt, err)
|
||||||
|
require.Equal(tt, expectedActive, active)
|
||||||
|
require.Equal(tt, uint64(0), current)
|
||||||
|
require.Equal(tt, uint64(0), previous)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("bad votes in last two epochs", func(tt *testing.T) {
|
||||||
|
copy(cp, []byte{0xFF ^ (1 << targetFlag), 0xFF ^ (1 << targetFlag), 0xFF ^ (1 << targetFlag), 0x00})
|
||||||
|
copy(pp, []byte{0x00, 0x00, 0x00, 0x00})
|
||||||
|
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, validators, 1)
|
||||||
|
require.NoError(tt, err)
|
||||||
|
require.Equal(tt, expectedActive, active)
|
||||||
|
require.Equal(tt, uint64(0), current)
|
||||||
|
require.Equal(tt, uint64(0), previous)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("two votes in last epoch", func(tt *testing.T) {
|
||||||
|
copy(cp, []byte{0xFF ^ (1 << targetFlag), 0xFF ^ (1 << targetFlag), 0xFF ^ (1 << targetFlag), 0x00, 1 << targetFlag, 1 << targetFlag})
|
||||||
|
copy(pp, []byte{0x00, 0x00, 0x00, 0x00, 0xFF ^ (1 << targetFlag)})
|
||||||
|
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, validators, 1)
|
||||||
|
require.NoError(tt, err)
|
||||||
|
require.Equal(tt, expectedActive, active)
|
||||||
|
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, current)
|
||||||
|
require.Equal(tt, uint64(0), previous)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("two votes in previous epoch", func(tt *testing.T) {
|
||||||
|
copy(cp, []byte{0x00, 0x00, 0x00, 0x00, 0xFF ^ (1 << targetFlag), 0x00})
|
||||||
|
copy(pp, []byte{0xFF ^ (1 << targetFlag), 0xFF ^ (1 << targetFlag), 0xFF ^ (1 << targetFlag), 0x00, 1 << targetFlag, 1 << targetFlag})
|
||||||
|
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, validators, 1)
|
||||||
|
require.NoError(tt, err)
|
||||||
|
require.Equal(tt, expectedActive, active)
|
||||||
|
require.Equal(tt, uint64(0), current)
|
||||||
|
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, previous)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("votes in both epochs, decreased balance in first validator", func(tt *testing.T) {
|
||||||
|
validators[0].EffectiveBalance = params.BeaconConfig().MaxEffectiveBalance - params.BeaconConfig().MinDepositAmount
|
||||||
|
copy(cp, []byte{0xFF, 0xFF, 0x00, 0x00, 0xFF ^ (1 << targetFlag), 0})
|
||||||
|
copy(pp, []byte{0xFF ^ (1 << targetFlag), 0xFF ^ (1 << targetFlag), 0xFF ^ (1 << targetFlag), 0x00, 0xFF, 0xFF})
|
||||||
|
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, validators, 1)
|
||||||
|
require.NoError(tt, err)
|
||||||
|
expectedActive -= params.BeaconConfig().MinDepositAmount
|
||||||
|
require.Equal(tt, expectedActive, active)
|
||||||
|
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance-params.BeaconConfig().MinDepositAmount, current)
|
||||||
|
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, previous)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("slash a validator", func(tt *testing.T) {
|
||||||
|
validators[1].Slashed = true
|
||||||
|
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, validators, 1)
|
||||||
|
require.NoError(tt, err)
|
||||||
|
expectedActive -= params.BeaconConfig().MaxEffectiveBalance
|
||||||
|
require.Equal(tt, expectedActive, active)
|
||||||
|
require.Equal(tt, params.BeaconConfig().MaxEffectiveBalance-params.BeaconConfig().MinDepositAmount, current)
|
||||||
|
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, previous)
|
||||||
|
})
|
||||||
|
t.Run("Exit a validator", func(tt *testing.T) {
|
||||||
|
validators[4].ExitEpoch = 1
|
||||||
|
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, validators, 2)
|
||||||
|
require.NoError(tt, err)
|
||||||
|
expectedActive -= params.BeaconConfig().MaxEffectiveBalance
|
||||||
|
require.Equal(tt, expectedActive, active)
|
||||||
|
require.Equal(tt, params.BeaconConfig().MaxEffectiveBalance-params.BeaconConfig().MinDepositAmount, current)
|
||||||
|
require.Equal(tt, params.BeaconConfig().MaxEffectiveBalance, previous)
|
||||||
|
})
|
||||||
|
}
|
@ -63,6 +63,8 @@ func TestNilState_NoPanic(t *testing.T) {
|
|||||||
_ = st.PreviousJustifiedCheckpoint()
|
_ = st.PreviousJustifiedCheckpoint()
|
||||||
_ = st.CurrentJustifiedCheckpoint()
|
_ = st.CurrentJustifiedCheckpoint()
|
||||||
_ = st.FinalizedCheckpoint()
|
_ = st.FinalizedCheckpoint()
|
||||||
|
_, _, _, err = st.UnrealizedCheckpointBalances()
|
||||||
|
_ = err
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T) {
|
func TestBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T) {
|
||||||
|
@ -15,6 +15,11 @@ func (*BeaconState) PreviousEpochParticipation() ([]byte, error) {
|
|||||||
return nil, errors.New("PreviousEpochParticipation is not supported for phase 0 beacon state")
|
return nil, errors.New("PreviousEpochParticipation is not supported for phase 0 beacon state")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnrealizedCheckpointBalances is not supported for phase 0 beacon state.
|
||||||
|
func (*BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, error) {
|
||||||
|
return 0, 0, 0, errors.New("UnrealizedCheckpointBalances is not supported for phase0 beacon state")
|
||||||
|
}
|
||||||
|
|
||||||
// InactivityScores is not supported for phase 0 beacon state.
|
// InactivityScores is not supported for phase 0 beacon state.
|
||||||
func (*BeaconState) InactivityScores() ([]uint64, error) {
|
func (*BeaconState) InactivityScores() ([]uint64, error) {
|
||||||
return nil, errors.New("InactivityScores is not supported for phase 0 beacon state")
|
return nil, errors.New("InactivityScores is not supported for phase 0 beacon state")
|
||||||
|
@ -5,6 +5,7 @@ go_library(
|
|||||||
srcs = [
|
srcs = [
|
||||||
"deprecated_getters.go",
|
"deprecated_getters.go",
|
||||||
"deprecated_setters.go",
|
"deprecated_setters.go",
|
||||||
|
"error.go",
|
||||||
"field_roots.go",
|
"field_roots.go",
|
||||||
"getters_block.go",
|
"getters_block.go",
|
||||||
"getters_checkpoint.go",
|
"getters_checkpoint.go",
|
||||||
@ -32,6 +33,7 @@ go_library(
|
|||||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/v2",
|
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/v2",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//beacon-chain/core/time:go_default_library",
|
||||||
"//beacon-chain/state:go_default_library",
|
"//beacon-chain/state:go_default_library",
|
||||||
"//beacon-chain/state/fieldtrie:go_default_library",
|
"//beacon-chain/state/fieldtrie:go_default_library",
|
||||||
"//beacon-chain/state/state-native:go_default_library",
|
"//beacon-chain/state/state-native:go_default_library",
|
||||||
@ -62,6 +64,7 @@ go_test(
|
|||||||
"deprecated_setters_test.go",
|
"deprecated_setters_test.go",
|
||||||
"getters_block_test.go",
|
"getters_block_test.go",
|
||||||
"getters_checkpoint_test.go",
|
"getters_checkpoint_test.go",
|
||||||
|
"getters_participation_test.go",
|
||||||
"getters_test.go",
|
"getters_test.go",
|
||||||
"getters_validator_test.go",
|
"getters_validator_test.go",
|
||||||
"proofs_test.go",
|
"proofs_test.go",
|
||||||
|
5
beacon-chain/state/v2/error.go
Normal file
5
beacon-chain/state/v2/error.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package v2
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var ErrNilParticipation = errors.New("Nil epoch participation in state")
|
@ -1,5 +1,10 @@
|
|||||||
package v2
|
package v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
|
||||||
|
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||||
|
)
|
||||||
|
|
||||||
// CurrentEpochParticipation corresponding to participation bits on the beacon chain.
|
// CurrentEpochParticipation corresponding to participation bits on the beacon chain.
|
||||||
func (b *BeaconState) CurrentEpochParticipation() ([]byte, error) {
|
func (b *BeaconState) CurrentEpochParticipation() ([]byte, error) {
|
||||||
if !b.hasInnerState() {
|
if !b.hasInnerState() {
|
||||||
@ -30,6 +35,26 @@ func (b *BeaconState) PreviousEpochParticipation() ([]byte, error) {
|
|||||||
return b.previousEpochParticipation(), nil
|
return b.previousEpochParticipation(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnrealizedCheckpointBalances returns the total balances: active, target attested in
|
||||||
|
// current epoch and target attested in previous epoch. This function is used to
|
||||||
|
// compute the "unrealized justification" that a synced Beacon Block will have.
|
||||||
|
func (b *BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, error) {
|
||||||
|
if !b.hasInnerState() {
|
||||||
|
return 0, 0, 0, ErrNilInnerState
|
||||||
|
}
|
||||||
|
b.lock.RLock()
|
||||||
|
defer b.lock.RUnlock()
|
||||||
|
|
||||||
|
cp := b.state.CurrentEpochParticipation
|
||||||
|
pp := b.state.PreviousEpochParticipation
|
||||||
|
if cp == nil || pp == nil {
|
||||||
|
return 0, 0, 0, ErrNilParticipation
|
||||||
|
}
|
||||||
|
currentEpoch := time.CurrentEpoch(b)
|
||||||
|
return stateutil.UnrealizedCheckpointBalances(cp, pp, b.state.Validators, currentEpoch)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// currentEpochParticipation corresponding to participation bits on the beacon chain.
|
// currentEpochParticipation corresponding to participation bits on the beacon chain.
|
||||||
// This assumes that a lock is already held on BeaconState.
|
// This assumes that a lock is already held on BeaconState.
|
||||||
func (b *BeaconState) currentEpochParticipation() []byte {
|
func (b *BeaconState) currentEpochParticipation() []byte {
|
||||||
|
64
beacon-chain/state/v2/getters_participation_test.go
Normal file
64
beacon-chain/state/v2/getters_participation_test.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/prysmaticlabs/prysm/config/params"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||||
|
"github.com/prysmaticlabs/prysm/testing/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestState_UnrealizedCheckpointBalances(t *testing.T) {
|
||||||
|
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||||
|
balances := make([]uint64, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||||
|
for i := 0; i < len(validators); i++ {
|
||||||
|
validators[i] = ðpb.Validator{
|
||||||
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||||
|
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||||
|
}
|
||||||
|
balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
||||||
|
}
|
||||||
|
base := ðpb.BeaconStateAltair{
|
||||||
|
Slot: 2,
|
||||||
|
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||||
|
|
||||||
|
Validators: validators,
|
||||||
|
CurrentEpochParticipation: make([]byte, params.BeaconConfig().MinGenesisActiveValidatorCount),
|
||||||
|
PreviousEpochParticipation: make([]byte, params.BeaconConfig().MinGenesisActiveValidatorCount),
|
||||||
|
Balances: balances,
|
||||||
|
}
|
||||||
|
state, err := InitializeFromProto(base)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// No one voted in the last two epochs
|
||||||
|
allActive := params.BeaconConfig().MinGenesisActiveValidatorCount * params.BeaconConfig().MaxEffectiveBalance
|
||||||
|
active, previous, current, err := state.UnrealizedCheckpointBalances()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, allActive, active)
|
||||||
|
require.Equal(t, uint64(0), current)
|
||||||
|
require.Equal(t, uint64(0), previous)
|
||||||
|
|
||||||
|
// Add some votes in the last two epochs:
|
||||||
|
base.CurrentEpochParticipation[0] = 0xFF
|
||||||
|
base.PreviousEpochParticipation[0] = 0xFF
|
||||||
|
base.PreviousEpochParticipation[1] = 0xFF
|
||||||
|
|
||||||
|
state, err = InitializeFromProto(base)
|
||||||
|
require.NoError(t, err)
|
||||||
|
active, previous, current, err = state.UnrealizedCheckpointBalances()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, allActive, active)
|
||||||
|
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, current)
|
||||||
|
require.Equal(t, 2*params.BeaconConfig().MaxEffectiveBalance, previous)
|
||||||
|
|
||||||
|
// Slash some validators
|
||||||
|
validators[0].Slashed = true
|
||||||
|
state, err = InitializeFromProto(base)
|
||||||
|
require.NoError(t, err)
|
||||||
|
active, previous, current, err = state.UnrealizedCheckpointBalances()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, allActive-params.BeaconConfig().MaxEffectiveBalance, active)
|
||||||
|
require.Equal(t, uint64(0), current)
|
||||||
|
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, previous)
|
||||||
|
|
||||||
|
}
|
@ -74,6 +74,8 @@ func TestNilState_NoPanic(t *testing.T) {
|
|||||||
require.ErrorIs(t, ErrNilInnerState, err)
|
require.ErrorIs(t, ErrNilInnerState, err)
|
||||||
_, err = st.NextSyncCommittee()
|
_, err = st.NextSyncCommittee()
|
||||||
require.ErrorIs(t, ErrNilInnerState, err)
|
require.ErrorIs(t, ErrNilInnerState, err)
|
||||||
|
_, _, _, err = st.UnrealizedCheckpointBalances()
|
||||||
|
require.ErrorIs(t, ErrNilInnerState, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T) {
|
func TestBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T) {
|
||||||
|
@ -5,6 +5,7 @@ go_library(
|
|||||||
srcs = [
|
srcs = [
|
||||||
"deprecated_getters.go",
|
"deprecated_getters.go",
|
||||||
"deprecated_setters.go",
|
"deprecated_setters.go",
|
||||||
|
"error.go",
|
||||||
"field_roots.go",
|
"field_roots.go",
|
||||||
"getters_block.go",
|
"getters_block.go",
|
||||||
"getters_checkpoint.go",
|
"getters_checkpoint.go",
|
||||||
@ -34,6 +35,7 @@ go_library(
|
|||||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/v3",
|
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/v3",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//beacon-chain/core/time:go_default_library",
|
||||||
"//beacon-chain/state:go_default_library",
|
"//beacon-chain/state:go_default_library",
|
||||||
"//beacon-chain/state/fieldtrie:go_default_library",
|
"//beacon-chain/state/fieldtrie:go_default_library",
|
||||||
"//beacon-chain/state/state-native:go_default_library",
|
"//beacon-chain/state/state-native:go_default_library",
|
||||||
@ -64,6 +66,7 @@ go_test(
|
|||||||
"deprecated_setters_test.go",
|
"deprecated_setters_test.go",
|
||||||
"getters_block_test.go",
|
"getters_block_test.go",
|
||||||
"getters_checkpoint_test.go",
|
"getters_checkpoint_test.go",
|
||||||
|
"getters_participation_test.go",
|
||||||
"getters_test.go",
|
"getters_test.go",
|
||||||
"getters_validator_test.go",
|
"getters_validator_test.go",
|
||||||
"proofs_test.go",
|
"proofs_test.go",
|
||||||
|
5
beacon-chain/state/v3/error.go
Normal file
5
beacon-chain/state/v3/error.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package v3
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var ErrNilParticipation = errors.New("Nil epoch participation in state")
|
@ -1,5 +1,10 @@
|
|||||||
package v3
|
package v3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
|
||||||
|
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||||
|
)
|
||||||
|
|
||||||
// CurrentEpochParticipation corresponding to participation bits on the beacon chain.
|
// CurrentEpochParticipation corresponding to participation bits on the beacon chain.
|
||||||
func (b *BeaconState) CurrentEpochParticipation() ([]byte, error) {
|
func (b *BeaconState) CurrentEpochParticipation() ([]byte, error) {
|
||||||
if !b.hasInnerState() {
|
if !b.hasInnerState() {
|
||||||
@ -30,6 +35,26 @@ func (b *BeaconState) PreviousEpochParticipation() ([]byte, error) {
|
|||||||
return b.previousEpochParticipation(), nil
|
return b.previousEpochParticipation(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnrealizedCheckpointBalances returns the total balances: active, target attested in
|
||||||
|
// current epoch and target attested in previous epoch. This function is used to
|
||||||
|
// compute the "unrealized justification" that a synced Beacon Block will have.
|
||||||
|
func (b *BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, error) {
|
||||||
|
if !b.hasInnerState() {
|
||||||
|
return 0, 0, 0, ErrNilInnerState
|
||||||
|
}
|
||||||
|
b.lock.RLock()
|
||||||
|
defer b.lock.RUnlock()
|
||||||
|
|
||||||
|
cp := b.state.CurrentEpochParticipation
|
||||||
|
pp := b.state.PreviousEpochParticipation
|
||||||
|
if cp == nil || pp == nil {
|
||||||
|
return 0, 0, 0, ErrNilParticipation
|
||||||
|
}
|
||||||
|
currentEpoch := time.CurrentEpoch(b)
|
||||||
|
return stateutil.UnrealizedCheckpointBalances(cp, pp, b.state.Validators, currentEpoch)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// currentEpochParticipation corresponding to participation bits on the beacon chain.
|
// currentEpochParticipation corresponding to participation bits on the beacon chain.
|
||||||
// This assumes that a lock is already held on BeaconState.
|
// This assumes that a lock is already held on BeaconState.
|
||||||
func (b *BeaconState) currentEpochParticipation() []byte {
|
func (b *BeaconState) currentEpochParticipation() []byte {
|
||||||
|
64
beacon-chain/state/v3/getters_participation_test.go
Normal file
64
beacon-chain/state/v3/getters_participation_test.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package v3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/prysmaticlabs/prysm/config/params"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||||
|
"github.com/prysmaticlabs/prysm/testing/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestState_UnrealizedCheckpointBalances(t *testing.T) {
|
||||||
|
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||||
|
balances := make([]uint64, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||||
|
for i := 0; i < len(validators); i++ {
|
||||||
|
validators[i] = ðpb.Validator{
|
||||||
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||||
|
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||||
|
}
|
||||||
|
balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
||||||
|
}
|
||||||
|
base := ðpb.BeaconStateBellatrix{
|
||||||
|
Slot: 2,
|
||||||
|
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||||
|
|
||||||
|
Validators: validators,
|
||||||
|
CurrentEpochParticipation: make([]byte, params.BeaconConfig().MinGenesisActiveValidatorCount),
|
||||||
|
PreviousEpochParticipation: make([]byte, params.BeaconConfig().MinGenesisActiveValidatorCount),
|
||||||
|
Balances: balances,
|
||||||
|
}
|
||||||
|
state, err := InitializeFromProto(base)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// No one voted in the last two epochs
|
||||||
|
allActive := params.BeaconConfig().MinGenesisActiveValidatorCount * params.BeaconConfig().MaxEffectiveBalance
|
||||||
|
active, previous, current, err := state.UnrealizedCheckpointBalances()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, allActive, active)
|
||||||
|
require.Equal(t, uint64(0), current)
|
||||||
|
require.Equal(t, uint64(0), previous)
|
||||||
|
|
||||||
|
// Add some votes in the last two epochs:
|
||||||
|
base.CurrentEpochParticipation[0] = 0xFF
|
||||||
|
base.PreviousEpochParticipation[0] = 0xFF
|
||||||
|
base.PreviousEpochParticipation[1] = 0xFF
|
||||||
|
|
||||||
|
state, err = InitializeFromProto(base)
|
||||||
|
require.NoError(t, err)
|
||||||
|
active, previous, current, err = state.UnrealizedCheckpointBalances()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, allActive, active)
|
||||||
|
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, current)
|
||||||
|
require.Equal(t, 2*params.BeaconConfig().MaxEffectiveBalance, previous)
|
||||||
|
|
||||||
|
// Slash some validators
|
||||||
|
validators[0].Slashed = true
|
||||||
|
state, err = InitializeFromProto(base)
|
||||||
|
require.NoError(t, err)
|
||||||
|
active, previous, current, err = state.UnrealizedCheckpointBalances()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, allActive-params.BeaconConfig().MaxEffectiveBalance, active)
|
||||||
|
require.Equal(t, uint64(0), current)
|
||||||
|
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, previous)
|
||||||
|
|
||||||
|
}
|
@ -75,6 +75,8 @@ func TestNilState_NoPanic(t *testing.T) {
|
|||||||
require.ErrorIs(t, ErrNilInnerState, err)
|
require.ErrorIs(t, ErrNilInnerState, err)
|
||||||
_, err = st.LatestExecutionPayloadHeader()
|
_, err = st.LatestExecutionPayloadHeader()
|
||||||
require.ErrorIs(t, ErrNilInnerState, err)
|
require.ErrorIs(t, ErrNilInnerState, err)
|
||||||
|
_, _, _, err = st.UnrealizedCheckpointBalances()
|
||||||
|
require.ErrorIs(t, ErrNilInnerState, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user