mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 05:47:59 -05:00
Implement Justification and finalization Processing (#2448)
This commit is contained in:
@@ -9,7 +9,6 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
@@ -112,100 +111,6 @@ func ProcessEth1Data(state *pb.BeaconState) *pb.BeaconState {
|
||||
return state
|
||||
}
|
||||
|
||||
// ProcessJustificationAndFinalization processes for justified slot by comparing
|
||||
// epoch boundary balance and total balance.
|
||||
// First, update the justification bitfield:
|
||||
// Let new_justified_epoch = state.justified_epoch.
|
||||
// Set state.justification_bitfield = state.justification_bitfield << 1.
|
||||
// Set state.justification_bitfield |= 2 and new_justified_epoch = previous_epoch if
|
||||
// 3 * previous_epoch_boundary_attesting_balance >= 2 * previous_total_balance.
|
||||
// Set state.justification_bitfield |= 1 and new_justified_epoch = current_epoch if
|
||||
// 3 * current_epoch_boundary_attesting_balance >= 2 * current_total_balance.
|
||||
// Next, update last finalized epoch if possible:
|
||||
// Set state.finalized_epoch = state.previous_justified_epoch if (state.justification_bitfield >> 1) % 8
|
||||
// == 0b111 and state.previous_justified_epoch == previous_epoch - 2.
|
||||
// Set state.finalized_epoch = state.previous_justified_epoch if (state.justification_bitfield >> 1) % 4
|
||||
// == 0b11 and state.previous_justified_epoch == previous_epoch - 1.
|
||||
// Set state.finalized_epoch = state.justified_epoch if (state.justification_bitfield >> 0) % 8
|
||||
// == 0b111 and state.justified_epoch == previous_epoch - 1.
|
||||
// Set state.finalized_epoch = state.justified_epoch if (state.justification_bitfield >> 0) % 4
|
||||
// == 0b11 and state.justified_epoch == previous_epoch.
|
||||
// Finally, update the following:
|
||||
// Set state.previous_justified_epoch = state.justified_epoch.
|
||||
// Set state.justified_epoch = new_justified_epoch
|
||||
func ProcessJustificationAndFinalization(
|
||||
state *pb.BeaconState,
|
||||
thisEpochBoundaryAttestingBalance uint64,
|
||||
prevEpochBoundaryAttestingBalance uint64,
|
||||
prevTotalBalance uint64,
|
||||
totalBalance uint64,
|
||||
) (*pb.BeaconState, error) {
|
||||
|
||||
newJustifiedEpoch := state.CurrentJustifiedEpoch
|
||||
newFinalizedEpoch := state.FinalizedEpoch
|
||||
prevEpoch := helpers.PrevEpoch(state)
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
// Shifts all the bits over one to create a new bit for the recent epoch.
|
||||
state.JustificationBitfield <<= 1
|
||||
// If prev prev epoch was justified then we ensure the 2nd bit in the bitfield is set,
|
||||
// assign new justified slot to 2 * SLOTS_PER_EPOCH before.
|
||||
if 3*prevEpochBoundaryAttestingBalance >= 2*prevTotalBalance {
|
||||
state.JustificationBitfield |= 2
|
||||
newJustifiedEpoch = prevEpoch
|
||||
}
|
||||
// If this epoch was justified then we ensure the 1st bit in the bitfield is set,
|
||||
// assign new justified slot to 1 * SLOTS_PER_EPOCH before.
|
||||
if 3*thisEpochBoundaryAttestingBalance >= 2*totalBalance {
|
||||
state.JustificationBitfield |= 1
|
||||
newJustifiedEpoch = currentEpoch
|
||||
}
|
||||
|
||||
// Process finality.
|
||||
// When the 2nd, 3rd and 4th most epochs are all justified, the 2nd can finalize the 4th epoch
|
||||
// as a source.
|
||||
if state.PreviousJustifiedEpoch == prevEpoch-2 &&
|
||||
(state.JustificationBitfield>>1)%8 == 7 {
|
||||
newFinalizedEpoch = state.PreviousJustifiedEpoch
|
||||
}
|
||||
// When the 2nd and 3rd most epochs are all justified, the 2nd can finalize the 3rd epoch
|
||||
// as a source.
|
||||
if state.PreviousJustifiedEpoch == prevEpoch-1 &&
|
||||
(state.JustificationBitfield>>1)%4 == 3 {
|
||||
newFinalizedEpoch = state.PreviousJustifiedEpoch
|
||||
}
|
||||
// When the 1st, 2nd and 3rd most epochs are all justified, the 1st can finalize the 3rd epoch
|
||||
// as a source.
|
||||
if state.CurrentJustifiedEpoch == prevEpoch-1 &&
|
||||
(state.JustificationBitfield>>0)%8 == 7 {
|
||||
newFinalizedEpoch = state.CurrentJustifiedEpoch
|
||||
}
|
||||
// When the 1st and 2nd most epochs are all justified, the 1st can finalize the 2nd epoch
|
||||
// as a source.
|
||||
if state.CurrentJustifiedEpoch == prevEpoch &&
|
||||
(state.JustificationBitfield>>0)%4 == 3 {
|
||||
newFinalizedEpoch = state.CurrentJustifiedEpoch
|
||||
}
|
||||
state.PreviousJustifiedEpoch = state.CurrentJustifiedEpoch
|
||||
state.PreviousJustifiedRoot = state.CurrentJustifiedRoot
|
||||
if newJustifiedEpoch != state.CurrentJustifiedEpoch {
|
||||
state.CurrentJustifiedEpoch = newJustifiedEpoch
|
||||
newJustifedRoot, err := blocks.BlockRoot(state, helpers.StartSlot(newJustifiedEpoch))
|
||||
if err != nil {
|
||||
return state, err
|
||||
}
|
||||
state.CurrentJustifiedRoot = newJustifedRoot
|
||||
}
|
||||
if newFinalizedEpoch != state.FinalizedEpoch {
|
||||
state.FinalizedEpoch = newFinalizedEpoch
|
||||
newFinalizedRoot, err := blocks.BlockRoot(state, helpers.StartSlot(newFinalizedEpoch))
|
||||
if err != nil {
|
||||
return state, err
|
||||
}
|
||||
state.FinalizedRoot = newFinalizedRoot
|
||||
}
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// ProcessCrosslinks goes through each crosslink committee and check
|
||||
// crosslink committee's attested balance * 3 is greater than total balance *2.
|
||||
// If it's greater then beacon node updates crosslink committee with
|
||||
@@ -386,6 +291,119 @@ func UpdateLatestActiveIndexRoots(state *pb.BeaconState) (*pb.BeaconState, error
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// ProcessJustificationFinalization processes justification and finalization during
|
||||
// epoch processing. This is where a beacon node can justify and finalize a new epoch.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def process_justification_and_finalization(state: BeaconState) -> None:
|
||||
// if get_current_epoch(state) <= GENESIS_EPOCH + 1:
|
||||
// return
|
||||
//
|
||||
// previous_epoch = get_previous_epoch(state)
|
||||
// current_epoch = get_current_epoch(state)
|
||||
// old_previous_justified_epoch = state.previous_justified_epoch
|
||||
// old_current_justified_epoch = state.current_justified_epoch
|
||||
//
|
||||
// # Process justifications
|
||||
// state.previous_justified_epoch = state.current_justified_epoch
|
||||
// state.previous_justified_root = state.current_justified_root
|
||||
// state.justification_bitfield = (state.justification_bitfield << 1) % 2**64
|
||||
// previous_epoch_matching_target_balance = get_attesting_balance(state, get_matching_target_attestations(state, previous_epoch))
|
||||
// if previous_epoch_matching_target_balance * 3 >= get_total_active_balance(state) * 2:
|
||||
// state.current_justified_epoch = previous_epoch
|
||||
// state.current_justified_root = get_block_root(state, state.current_justified_epoch)
|
||||
// state.justification_bitfield |= (1 << 1)
|
||||
// current_epoch_matching_target_balance = get_attesting_balance(state, get_matching_target_attestations(state, current_epoch))
|
||||
// if current_epoch_matching_target_balance * 3 >= get_total_active_balance(state) * 2:
|
||||
// state.current_justified_epoch = current_epoch
|
||||
// state.current_justified_root = get_block_root(state, state.current_justified_epoch)
|
||||
// state.justification_bitfield |= (1 << 0)
|
||||
//
|
||||
// # Process finalizations
|
||||
// bitfield = state.justification_bitfield
|
||||
// # The 2nd/3rd/4th most recent epochs are justified, the 2nd using the 4th as source
|
||||
// if (bitfield >> 1) % 8 == 0b111 and old_previous_justified_epoch == current_epoch - 3:
|
||||
// state.finalized_epoch = old_previous_justified_epoch
|
||||
// state.finalized_root = get_block_root(state, state.finalized_epoch)
|
||||
// # The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as source
|
||||
// if (bitfield >> 1) % 4 == 0b11 and old_previous_justified_epoch == current_epoch - 2:
|
||||
// state.finalized_epoch = old_previous_justified_epoch
|
||||
// state.finalized_root = get_block_root(state, state.finalized_epoch)
|
||||
// # The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as source
|
||||
// if (bitfield >> 0) % 8 == 0b111 and old_current_justified_epoch == current_epoch - 2:
|
||||
// state.finalized_epoch = old_current_justified_epoch
|
||||
// state.finalized_root = get_block_root(state, state.finalized_epoch)
|
||||
// # The 1st/2nd most recent epochs are justified, the 1st using the 2nd as source
|
||||
// if (bitfield >> 0) % 4 == 0b11 and old_current_justified_epoch == current_epoch - 1:
|
||||
// state.finalized_epoch = old_current_justified_epoch
|
||||
// state.finalized_root = get_block_root(state, state.finalized_epoch)
|
||||
func ProcessJustificationFinalization(state *pb.BeaconState, prevAttestedBal uint64, currAttestedBal uint64) (
|
||||
*pb.BeaconState, error) {
|
||||
// There's no reason to process justification until the 3rd epoch.
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
if currentEpoch <= params.BeaconConfig().GenesisEpoch+1 {
|
||||
return state, nil
|
||||
}
|
||||
|
||||
prevEpoch := helpers.PrevEpoch(state)
|
||||
totalBal := totalActiveBalance(state)
|
||||
oldPrevJustifiedEpoch := state.PreviousJustifiedEpoch
|
||||
oldPrevJustifiedRoot := state.PreviousJustifiedRoot
|
||||
oldCurrJustifiedEpoch := state.CurrentJustifiedEpoch
|
||||
oldCurrJustifiedRoot := state.CurrentJustifiedRoot
|
||||
state.PreviousJustifiedEpoch = state.CurrentJustifiedEpoch
|
||||
state.PreviousJustifiedRoot = state.CurrentJustifiedRoot
|
||||
state.JustificationBitfield = (state.JustificationBitfield << 1) % (1 << 63)
|
||||
// Process justification.
|
||||
if 3*prevAttestedBal >= 2*totalBal {
|
||||
state.CurrentJustifiedEpoch = prevEpoch
|
||||
blockRoot, err := helpers.BlockRoot(state, prevEpoch)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get block root for previous epoch %d: %v",
|
||||
prevEpoch, err)
|
||||
}
|
||||
state.CurrentJustifiedRoot = blockRoot
|
||||
state.JustificationBitfield |= 2
|
||||
}
|
||||
if 3*currAttestedBal >= 2*totalBal {
|
||||
state.CurrentJustifiedEpoch = currentEpoch
|
||||
blockRoot, err := helpers.BlockRoot(state, currentEpoch)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get block root for current epoch %d: %v",
|
||||
prevEpoch, err)
|
||||
}
|
||||
state.CurrentJustifiedRoot = blockRoot
|
||||
state.JustificationBitfield |= 1
|
||||
}
|
||||
// Process finalization.
|
||||
bitfield := state.JustificationBitfield
|
||||
// When the 2nd, 3rd and 4th most recent epochs are all justified,
|
||||
// 2nd epoch can finalize the 4th epoch as a source.
|
||||
if oldPrevJustifiedEpoch == currentEpoch-3 && (bitfield>>1)%8 == 7 {
|
||||
state.FinalizedEpoch = oldPrevJustifiedEpoch
|
||||
state.FinalizedRoot = oldPrevJustifiedRoot
|
||||
}
|
||||
// when 2nd and 3rd most recent epochs are all justified,
|
||||
// 2nd epoch can finalize 3rd as a source.
|
||||
if oldPrevJustifiedEpoch == currentEpoch-2 && (bitfield>>1)%4 == 3 {
|
||||
state.FinalizedEpoch = oldPrevJustifiedEpoch
|
||||
state.FinalizedRoot = oldPrevJustifiedRoot
|
||||
}
|
||||
// when 1st, 2nd and 3rd most recent epochs are all justified,
|
||||
// 1st epoch can finalize 3rd as a source.
|
||||
if oldCurrJustifiedEpoch == currentEpoch-2 && (bitfield>>0)%8 == 7 {
|
||||
state.FinalizedEpoch = oldCurrJustifiedEpoch
|
||||
state.FinalizedRoot = oldCurrJustifiedRoot
|
||||
}
|
||||
// when 1st, 2nd most recent epochs are all justified,
|
||||
// 1st epoch can finalize 2nd as a source.
|
||||
if oldCurrJustifiedEpoch == currentEpoch-1 && (bitfield>>0)%4 == 3 {
|
||||
state.FinalizedEpoch = oldCurrJustifiedEpoch
|
||||
state.FinalizedRoot = oldCurrJustifiedRoot
|
||||
}
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// UpdateLatestSlashedBalances updates the latest slashed balances. It transfers
|
||||
// the amount from the current epoch index to next epoch index.
|
||||
//
|
||||
@@ -681,3 +699,11 @@ func attsForCrosslink(state *pb.BeaconState, crosslink *pb.Crosslink, atts []*pb
|
||||
}
|
||||
return crosslinkAtts
|
||||
}
|
||||
|
||||
// TotalActiveBalance returns the combined balances of all the active validators.
|
||||
// Spec pseudocode definition:
|
||||
// def get_total_active_balance(state: BeaconState) -> Gwei:
|
||||
// return get_total_balance(state, get_active_validator_indices(state, get_current_epoch(state)))
|
||||
func totalActiveBalance(state *pb.BeaconState) uint64 {
|
||||
return TotalBalance(state, helpers.ActiveValidatorIndices(state.ValidatorRegistry, helpers.CurrentEpoch(state)))
|
||||
}
|
||||
|
||||
@@ -211,67 +211,6 @@ func TestProcessEth1Data_InactionSlot(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessJustification_PreviousEpochJustified(t *testing.T) {
|
||||
if params.BeaconConfig().SlotsPerEpoch != 64 {
|
||||
t.Errorf("SlotsPerEpoch should be 64 for these tests to pass")
|
||||
}
|
||||
|
||||
var latestBlockRoots [][]byte
|
||||
|
||||
for i := uint64(0); i < params.BeaconConfig().LatestBlockRootsLength; i++ {
|
||||
latestBlockRoots = append(latestBlockRoots, []byte("a"))
|
||||
}
|
||||
|
||||
state := &pb.BeaconState{
|
||||
Slot: 300 + params.BeaconConfig().GenesisSlot,
|
||||
CurrentJustifiedEpoch: 3,
|
||||
JustificationBitfield: 4,
|
||||
LatestBlockRoots: latestBlockRoots,
|
||||
}
|
||||
newState, err := ProcessJustificationAndFinalization(
|
||||
state,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
)
|
||||
if err != nil {
|
||||
t.Errorf("Could not process justification and finalization of state %v", err)
|
||||
}
|
||||
|
||||
if newState.PreviousJustifiedEpoch != 3 {
|
||||
t.Errorf("New state's prev justified slot %d != old state's justified slot %d",
|
||||
newState.PreviousJustifiedEpoch, state.CurrentJustifiedEpoch)
|
||||
}
|
||||
// Since this epoch was justified (not prev), justified_epoch = slot_to_epoch(state.slot) -1.
|
||||
if newState.CurrentJustifiedEpoch != helpers.CurrentEpoch(state) {
|
||||
t.Errorf("New state's justified epoch %d != state's slot - SLOTS_PER_EPOCH: %d",
|
||||
newState.CurrentJustifiedEpoch, helpers.CurrentEpoch(state))
|
||||
}
|
||||
// The new JustificationBitfield is 11, it went from 0100 to 1011. Two 1's were appended because both
|
||||
// prev epoch and this epoch were justified.
|
||||
if newState.JustificationBitfield != 11 {
|
||||
t.Errorf("New state's justification bitfield %d != 11", newState.JustificationBitfield)
|
||||
}
|
||||
|
||||
// Assume for the case where only prev epoch got justified. Verify
|
||||
// justified_epoch = slot_to_epoch(state.slot) -2.
|
||||
newState, err = ProcessJustificationAndFinalization(
|
||||
state,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
)
|
||||
if err != nil {
|
||||
t.Errorf("Could not process justification and finalization of state %v", err)
|
||||
}
|
||||
if newState.CurrentJustifiedEpoch != helpers.CurrentEpoch(state)-1 {
|
||||
t.Errorf("New state's justified epoch %d != state's epoch -2: %d",
|
||||
newState.CurrentJustifiedEpoch, helpers.CurrentEpoch(state)-1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessCrosslinks_CrosslinksCorrectEpoch(t *testing.T) {
|
||||
state := buildState(5, params.BeaconConfig().DepositsForChainStart)
|
||||
state.LatestCrosslinks = []*pb.Crosslink{{}, {}}
|
||||
@@ -1099,3 +1038,146 @@ func TestWinningCrosslink_CanGetWinningRoot(t *testing.T) {
|
||||
t.Errorf("Did not get genesis crosslink, got: %v", winner)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessJustificationFinalization_LessThan2ndEpoch(t *testing.T) {
|
||||
state := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch,
|
||||
}
|
||||
newState, err := ProcessJustificationFinalization(state, 0, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(state, newState) {
|
||||
t.Error("Did not get the original state")
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessJustificationFinalization_CantJustifyFinalize(t *testing.T) {
|
||||
e := params.BeaconConfig().FarFutureEpoch
|
||||
a := params.BeaconConfig().MaxDepositAmount
|
||||
state := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().GenesisSlot + params.BeaconConfig().SlotsPerEpoch*2,
|
||||
PreviousJustifiedEpoch: params.BeaconConfig().GenesisEpoch,
|
||||
PreviousJustifiedRoot: params.BeaconConfig().ZeroHash[:],
|
||||
CurrentJustifiedEpoch: params.BeaconConfig().GenesisEpoch,
|
||||
CurrentJustifiedRoot: params.BeaconConfig().ZeroHash[:],
|
||||
ValidatorRegistry: []*pb.Validator{{ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}},
|
||||
Balances: []uint64{a, a, a, a}, // validator total balance should be 128000000000
|
||||
}
|
||||
// Since Attested balances are less than total balances, nothing happened.
|
||||
newState, err := ProcessJustificationFinalization(state, 0, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(state, newState) {
|
||||
t.Error("Did not get the original state")
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessJustificationFinalization_NoBlockRootCurrentEpoch(t *testing.T) {
|
||||
e := params.BeaconConfig().FarFutureEpoch
|
||||
a := params.BeaconConfig().MaxDepositAmount
|
||||
blockRoots := make([][]byte, params.BeaconConfig().SlotsPerEpoch*2+1)
|
||||
for i := 0; i < len(blockRoots); i++ {
|
||||
blockRoots[i] = []byte{byte(i)}
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().GenesisSlot + params.BeaconConfig().SlotsPerEpoch*2,
|
||||
PreviousJustifiedEpoch: params.BeaconConfig().GenesisEpoch,
|
||||
PreviousJustifiedRoot: params.BeaconConfig().ZeroHash[:],
|
||||
CurrentJustifiedEpoch: params.BeaconConfig().GenesisEpoch,
|
||||
CurrentJustifiedRoot: params.BeaconConfig().ZeroHash[:],
|
||||
JustificationBitfield: 3,
|
||||
ValidatorRegistry: []*pb.Validator{{ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}},
|
||||
Balances: []uint64{a, a, a, a}, // validator total balance should be 128000000000
|
||||
LatestBlockRoots: blockRoots,
|
||||
}
|
||||
attestedBalance := 4 * e * 3 / 2
|
||||
_, err := ProcessJustificationFinalization(state, 0, attestedBalance)
|
||||
want := "could not get block root for current epoch"
|
||||
if !strings.Contains(err.Error(), want) {
|
||||
t.Fatal("Did not receive correct error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessJustificationFinalization_JustifyCurrentEpoch(t *testing.T) {
|
||||
e := params.BeaconConfig().FarFutureEpoch
|
||||
a := params.BeaconConfig().MaxDepositAmount
|
||||
blockRoots := make([][]byte, params.BeaconConfig().SlotsPerEpoch*2+1)
|
||||
for i := 0; i < len(blockRoots); i++ {
|
||||
blockRoots[i] = []byte{byte(i)}
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().GenesisSlot + params.BeaconConfig().SlotsPerEpoch*2 + 1,
|
||||
PreviousJustifiedEpoch: params.BeaconConfig().GenesisEpoch,
|
||||
PreviousJustifiedRoot: params.BeaconConfig().ZeroHash[:],
|
||||
CurrentJustifiedEpoch: params.BeaconConfig().GenesisEpoch,
|
||||
CurrentJustifiedRoot: params.BeaconConfig().ZeroHash[:],
|
||||
JustificationBitfield: 3,
|
||||
ValidatorRegistry: []*pb.Validator{{ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}},
|
||||
Balances: []uint64{a, a, a, a}, // validator total balance should be 128000000000
|
||||
LatestBlockRoots: blockRoots,
|
||||
}
|
||||
attestedBalance := 4 * e * 3 / 2
|
||||
newState, err := ProcessJustificationFinalization(state, 0, attestedBalance)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(newState.CurrentJustifiedRoot, []byte{byte(128)}) {
|
||||
t.Errorf("Wanted current justified root: %v, got: %v",
|
||||
[]byte{byte(128)}, newState.CurrentJustifiedRoot)
|
||||
}
|
||||
if newState.CurrentJustifiedEpoch != params.BeaconConfig().GenesisEpoch+2 {
|
||||
t.Errorf("Wanted justified epoch: %d, got: %d",
|
||||
params.BeaconConfig().GenesisEpoch+2, newState.CurrentJustifiedEpoch)
|
||||
}
|
||||
if !bytes.Equal(newState.FinalizedRoot, params.BeaconConfig().ZeroHash[:]) {
|
||||
t.Errorf("Wanted current finalized root: %v, got: %v",
|
||||
params.BeaconConfig().ZeroHash, newState.FinalizedRoot)
|
||||
}
|
||||
if newState.FinalizedEpoch != params.BeaconConfig().GenesisEpoch {
|
||||
t.Errorf("Wanted finalized epoch: %d, got: %d",
|
||||
params.BeaconConfig().GenesisEpoch, newState.FinalizedEpoch)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessJustificationFinalization_JustifyPrevEpoch(t *testing.T) {
|
||||
e := params.BeaconConfig().FarFutureEpoch
|
||||
a := params.BeaconConfig().MaxDepositAmount
|
||||
blockRoots := make([][]byte, params.BeaconConfig().SlotsPerEpoch*2+1)
|
||||
for i := 0; i < len(blockRoots); i++ {
|
||||
blockRoots[i] = []byte{byte(i)}
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().GenesisSlot + params.BeaconConfig().SlotsPerEpoch*2 + 1,
|
||||
PreviousJustifiedEpoch: params.BeaconConfig().GenesisEpoch,
|
||||
PreviousJustifiedRoot: params.BeaconConfig().ZeroHash[:],
|
||||
CurrentJustifiedEpoch: params.BeaconConfig().GenesisEpoch,
|
||||
CurrentJustifiedRoot: params.BeaconConfig().ZeroHash[:],
|
||||
JustificationBitfield: 3,
|
||||
ValidatorRegistry: []*pb.Validator{{ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}},
|
||||
Balances: []uint64{a, a, a, a}, // validator total balance should be 128000000000
|
||||
LatestBlockRoots: blockRoots,
|
||||
}
|
||||
attestedBalance := 4 * e * 3 / 2
|
||||
newState, err := ProcessJustificationFinalization(state, attestedBalance, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(newState.CurrentJustifiedRoot, []byte{byte(64)}) {
|
||||
t.Errorf("Wanted current justified root: %v, got: %v",
|
||||
[]byte{byte(128)}, newState.CurrentJustifiedRoot)
|
||||
}
|
||||
if newState.CurrentJustifiedEpoch != params.BeaconConfig().GenesisEpoch+1 {
|
||||
t.Errorf("Wanted justified epoch: %d, got: %d",
|
||||
params.BeaconConfig().GenesisEpoch+2, newState.CurrentJustifiedEpoch)
|
||||
}
|
||||
if !bytes.Equal(newState.FinalizedRoot, params.BeaconConfig().ZeroHash[:]) {
|
||||
t.Errorf("Wanted current finalized root: %v, got: %v",
|
||||
params.BeaconConfig().ZeroHash, newState.FinalizedRoot)
|
||||
}
|
||||
if newState.FinalizedEpoch != params.BeaconConfig().GenesisEpoch {
|
||||
t.Errorf("Wanted finalized epoch: %d, got: %d",
|
||||
params.BeaconConfig().GenesisEpoch, newState.FinalizedEpoch)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ func BlockRootAtSlot(state *pb.BeaconState, slot uint64) ([]byte, error) {
|
||||
state.Slot-params.BeaconConfig().GenesisSlot,
|
||||
)
|
||||
}
|
||||
|
||||
return state.LatestBlockRoots[slot%params.BeaconConfig().SlotsPerHistoricalRoot], nil
|
||||
}
|
||||
|
||||
|
||||
@@ -305,8 +305,6 @@ func ProcessEpoch(ctx context.Context, state *pb.BeaconState, block *pb.BeaconBl
|
||||
|
||||
// Calculate the attesting balances for previous and current epoch.
|
||||
currentBoundaryAttestingBalances := e.TotalBalance(state, currentBoundaryAttesterIndices)
|
||||
previousActiveValidatorIndices := helpers.ActiveValidatorIndices(state.ValidatorRegistry, prevEpoch)
|
||||
prevTotalBalance := e.TotalBalance(state, previousActiveValidatorIndices)
|
||||
prevEpochAttestingBalance := e.TotalBalance(state, prevEpochAttesterIndices)
|
||||
prevEpochBoundaryAttestingBalances := e.TotalBalance(state, prevEpochBoundaryAttesterIndices)
|
||||
prevEpochHeadAttestingBalances := e.TotalBalance(state, prevEpochHeadAttesterIndices)
|
||||
@@ -317,12 +315,10 @@ func ProcessEpoch(ctx context.Context, state *pb.BeaconState, block *pb.BeaconBl
|
||||
}
|
||||
|
||||
// Update justification and finality.
|
||||
state, err := e.ProcessJustificationAndFinalization(
|
||||
state, err := e.ProcessJustificationFinalization(
|
||||
state,
|
||||
currentBoundaryAttestingBalances,
|
||||
prevEpochAttestingBalance,
|
||||
prevTotalBalance,
|
||||
totalBalance,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not process justification and finalization of state: %v", err)
|
||||
|
||||
Reference in New Issue
Block a user