package state import ( v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" pbcomm "github.com/prysmaticlabs/prysm/proto/common" "github.com/prysmaticlabs/prysm/shared/params" ) // NewGenesisBeaconState initializes the beacon chain state for slot 0. func NewGenesisBeaconState(genesisValidatorRegistry []*pb.ValidatorRecord) (*pb.BeaconState, error) { // We seed the genesis state with a bunch of validators to // bootstrap the system. var err error if genesisValidatorRegistry == nil { genesisValidatorRegistry = v.InitialValidatorRegistry() } // Bootstrap attester indices for slots, each slot contains an array of attester indices. shardAndCommitteesForSlots, err := v.InitialShardAndCommitteesForSlots(genesisValidatorRegistry) if err != nil { return nil, err } // Bootstrap cross link records. var crosslinks []*pb.CrosslinkRecord for i := uint64(0); i < params.BeaconConfig().ShardCount; i++ { crosslinks = append(crosslinks, &pb.CrosslinkRecord{ ShardBlockRootHash32: make([]byte, 0, 32), Slot: 0, }) } var latestBlockHashes [][]byte for i := 0; i < 2*int(params.BeaconConfig().CycleLength); i++ { latestBlockHashes = append(latestBlockHashes, make([]byte, 0, 32)) } return &pb.BeaconState{ ValidatorRegistry: genesisValidatorRegistry, ValidatorRegistryLastChangeSlot: 0, ValidatorRegistryExitCount: 0, ValidatorRegistryDeltaChainTipHash32: make([]byte, 0, 32), RandaoMixHash32: make([]byte, 0, 32), NextSeedHash32: make([]byte, 0, 32), ShardAndCommitteesAtSlots: shardAndCommitteesForSlots, PersistentCommittees: []*pbcomm.Uint32List{}, PersistentCommitteeReassignments: []*pb.ShardReassignmentRecord{}, PreviousJustifiedSlot: 0, JustifiedSlot: 0, JustifiedSlotBitfield: 0, FinalizedSlot: 0, LatestCrosslinks: crosslinks, LastStateRecalculationSlot: 0, LatestBlockRootHash32S: latestBlockHashes, LatestPenalizedExitBalances: []uint64{}, LatestAttestations: []*pb.PendingAttestationRecord{}, ProcessedPowReceiptRootHash32: []byte{}, CandidatePowReceiptRoots: []*pb.CandidatePoWReceiptRootRecord{}, GenesisTime: 0, ForkData: &pb.ForkData{ PreForkVersion: params.BeaconConfig().InitialForkVersion, PostForkVersion: params.BeaconConfig().InitialForkVersion, ForkSlot: params.BeaconConfig().InitialForkSlot, }, Slot: 0, }, nil } // CalculateNewBlockHashes builds a new slice of recent block hashes with the // provided block and the parent slot number. // // The algorithm is: // 1) shift the array by block.SlotNumber - parentSlot (i.e. truncate the // first by the number of slots that have occurred between the block and // its parent). // // 2) fill the array with the parent block hash for all values between the parent // slot and the block slot. // // Computation of the state hash depends on this feature that slots with // missing blocks have the block hash of the next block hash in the chain. // // For example, if we have a segment of recent block hashes that look like this // [0xF, 0x7, 0x0, 0x0, 0x5] // // Where 0x0 is an empty or missing hash where no block was produced in the // alloted slot. When storing the list (or at least when computing the hash of // the active state), the list should be back-filled as such: // // [0xF, 0x7, 0x5, 0x5, 0x5] func CalculateNewBlockHashes(state *pb.BeaconState, block *pb.BeaconBlock, parentSlot uint64) ([][]byte, error) { distance := block.GetSlot() - parentSlot existing := state.GetLatestBlockRootHash32S() update := existing[distance:] for len(update) < 2*int(params.BeaconConfig().CycleLength) { update = append(update, block.GetParentRootHash32()) } return update, nil } // IsValidatorSetChange checks if a validator set change transition can be processed. At that point, // validator shuffle will occur. func IsValidatorSetChange(state *pb.BeaconState, slotNumber uint64) bool { if state.GetFinalizedSlot() <= state.GetValidatorRegistryLastChangeSlot() { return false } if slotNumber-state.GetValidatorRegistryLastChangeSlot() < params.BeaconConfig().MinValidatorSetChangeInterval { return false } shardProcessed := map[uint64]bool{} for _, shardAndCommittee := range state.GetShardAndCommitteesAtSlots() { for _, committee := range shardAndCommittee.ArrayShardAndCommittee { shardProcessed[committee.Shard] = true } } crosslinks := state.GetLatestCrosslinks() for shard := range shardProcessed { if state.GetValidatorRegistryLastChangeSlot() >= crosslinks[shard].Slot { return false } } return true } // ClearAttestations removes attestations older than last state recalculation slot. func ClearAttestations(state *pb.BeaconState, lastStateRecalc uint64) []*pb.PendingAttestationRecord { existing := state.GetLatestAttestations() updatedAttestations := make([]*pb.PendingAttestationRecord, 0, len(existing)) for _, a := range existing { if a.GetData().GetSlot() >= lastStateRecalc { updatedAttestations = append(updatedAttestations, a) } } return updatedAttestations } // IsCycleTransition checks if a new cycle has been reached. At that point, // a new state transition will occur in the beacon chain. func IsCycleTransition(lastRecalcSlot uint64, slotNumber uint64) bool { return slotNumber >= lastRecalcSlot+params.BeaconConfig().CycleLength }