2018-12-23 22:51:04 +00:00
|
|
|
package state
|
|
|
|
|
|
|
|
import (
|
2019-01-05 05:39:34 +00:00
|
|
|
"encoding/binary"
|
2018-12-25 06:47:07 +00:00
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/gogo/protobuf/proto"
|
2019-01-05 05:39:34 +00:00
|
|
|
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
2019-01-06 15:25:43 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/state/stateutils"
|
2018-12-23 22:51:04 +00:00
|
|
|
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"
|
2018-12-25 06:47:07 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
2018-12-23 22:51:04 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/params"
|
|
|
|
)
|
|
|
|
|
2018-12-31 07:40:14 +00:00
|
|
|
// InitialBeaconState gets called when DepositsForChainStart count of
|
|
|
|
// full deposits were made to the deposit contract and the ChainStart log gets emitted.
|
|
|
|
func InitialBeaconState(
|
|
|
|
initialValidatorDeposits []*pb.Deposit,
|
|
|
|
genesisTime uint64,
|
2019-01-06 15:25:43 +00:00
|
|
|
processedPowReceiptRoot []byte,
|
|
|
|
) (*pb.BeaconState, error) {
|
|
|
|
latestRandaoMixes := make(
|
|
|
|
[][]byte,
|
|
|
|
params.BeaconConfig().LatestRandaoMixesLength,
|
|
|
|
)
|
2018-12-31 07:40:14 +00:00
|
|
|
for i := 0; i < len(latestRandaoMixes); i++ {
|
|
|
|
latestRandaoMixes[i] = params.BeaconConfig().ZeroHash[:]
|
|
|
|
}
|
|
|
|
|
|
|
|
latestVDFOutputs := make([][]byte,
|
|
|
|
params.BeaconConfig().LatestRandaoMixesLength/params.BeaconConfig().EpochLength)
|
|
|
|
for i := 0; i < len(latestVDFOutputs); i++ {
|
|
|
|
latestVDFOutputs[i] = params.BeaconConfig().ZeroHash[:]
|
|
|
|
}
|
|
|
|
|
|
|
|
latestCrosslinks := make([]*pb.CrosslinkRecord, params.BeaconConfig().ShardCount)
|
|
|
|
for i := 0; i < len(latestCrosslinks); i++ {
|
|
|
|
latestCrosslinks[i] = &pb.CrosslinkRecord{
|
2019-01-05 06:39:07 +00:00
|
|
|
Slot: params.BeaconConfig().GenesisSlot,
|
2018-12-31 07:40:14 +00:00
|
|
|
ShardBlockRootHash32: params.BeaconConfig().ZeroHash[:],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
latestBlockRoots := make([][]byte, params.BeaconConfig().LatestBlockRootsLength)
|
|
|
|
for i := 0; i < len(latestBlockRoots); i++ {
|
|
|
|
latestBlockRoots[i] = params.BeaconConfig().ZeroHash[:]
|
|
|
|
}
|
|
|
|
|
2019-01-05 06:39:07 +00:00
|
|
|
latestPenalizedExitBalances := make([]uint64, params.BeaconConfig().LatestPenalizedExitLength)
|
|
|
|
|
2018-12-31 07:40:14 +00:00
|
|
|
state := &pb.BeaconState{
|
|
|
|
// Misc fields.
|
2019-01-05 06:39:07 +00:00
|
|
|
Slot: params.BeaconConfig().GenesisSlot,
|
2018-12-31 07:40:14 +00:00
|
|
|
GenesisTime: genesisTime,
|
|
|
|
ForkData: &pb.ForkData{
|
2019-01-05 06:39:07 +00:00
|
|
|
PreForkVersion: params.BeaconConfig().GenesisForkVersion,
|
|
|
|
PostForkVersion: params.BeaconConfig().GenesisForkVersion,
|
|
|
|
ForkSlot: params.BeaconConfig().GenesisSlot,
|
2018-12-31 07:40:14 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
// Validator registry fields.
|
|
|
|
ValidatorRegistry: []*pb.ValidatorRecord{},
|
|
|
|
ValidatorBalances: []uint64{},
|
2019-01-05 06:39:07 +00:00
|
|
|
ValidatorRegistryLastChangeSlot: params.BeaconConfig().GenesisSlot,
|
2018-12-31 07:40:14 +00:00
|
|
|
ValidatorRegistryExitCount: 0,
|
|
|
|
ValidatorRegistryDeltaChainTipHash32: params.BeaconConfig().ZeroHash[:],
|
|
|
|
|
|
|
|
// Randomness and committees.
|
|
|
|
LatestRandaoMixesHash32S: latestRandaoMixes,
|
|
|
|
LatestVdfOutputs: latestVDFOutputs,
|
|
|
|
ShardAndCommitteesAtSlots: []*pb.ShardAndCommitteeArray{},
|
|
|
|
PersistentCommittees: []*pbcomm.Uint32List{},
|
|
|
|
PersistentCommitteeReassignments: []*pb.ShardReassignmentRecord{},
|
|
|
|
|
|
|
|
// Proof of custody.
|
|
|
|
// Place holder, proof of custody challenge is defined in phase 1.
|
|
|
|
// This list will remain empty through out phase 0.
|
|
|
|
PocChallenges: []*pb.ProofOfCustodyChallenge{},
|
|
|
|
|
|
|
|
// Finality.
|
2019-01-05 06:39:07 +00:00
|
|
|
PreviousJustifiedSlot: params.BeaconConfig().GenesisSlot,
|
|
|
|
JustifiedSlot: params.BeaconConfig().GenesisSlot,
|
2018-12-31 07:40:14 +00:00
|
|
|
JustificationBitfield: 0,
|
2019-01-05 06:39:07 +00:00
|
|
|
FinalizedSlot: params.BeaconConfig().GenesisSlot,
|
2018-12-31 07:40:14 +00:00
|
|
|
|
|
|
|
// Recent state.
|
|
|
|
LatestCrosslinks: latestCrosslinks,
|
|
|
|
LatestBlockRootHash32S: latestBlockRoots,
|
2019-01-05 06:39:07 +00:00
|
|
|
LatestPenalizedExitBalances: latestPenalizedExitBalances,
|
2018-12-31 07:40:14 +00:00
|
|
|
LatestAttestations: []*pb.PendingAttestationRecord{},
|
|
|
|
BatchedBlockRootHash32S: [][]byte{},
|
|
|
|
|
|
|
|
// PoW receipt root.
|
|
|
|
ProcessedPowReceiptRootHash32: processedPowReceiptRoot,
|
|
|
|
CandidatePowReceiptRoots: []*pb.CandidatePoWReceiptRootRecord{},
|
|
|
|
}
|
|
|
|
|
2019-01-05 06:39:07 +00:00
|
|
|
// Process initial deposits.
|
2018-12-31 07:40:14 +00:00
|
|
|
var err error
|
2019-01-06 15:25:43 +00:00
|
|
|
validatorMap := stateutils.ValidatorIndexMap(state)
|
2018-12-31 07:40:14 +00:00
|
|
|
for _, deposit := range initialValidatorDeposits {
|
2019-01-05 05:39:34 +00:00
|
|
|
depositData := deposit.DepositData
|
|
|
|
depositInput, err := b.DecodeDepositInput(depositData)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("could not decode deposit input: %v", err)
|
|
|
|
}
|
|
|
|
// depositData consists of depositInput []byte + depositValue [8]byte +
|
|
|
|
// depositTimestamp [8]byte.
|
|
|
|
depositValue := depositData[len(depositData)-16 : len(depositData)-8]
|
2019-01-05 06:39:07 +00:00
|
|
|
state, err = v.ProcessDeposit(
|
2018-12-31 07:40:14 +00:00
|
|
|
state,
|
2019-01-06 15:25:43 +00:00
|
|
|
validatorMap,
|
2019-01-05 05:39:34 +00:00
|
|
|
depositInput.Pubkey,
|
|
|
|
binary.BigEndian.Uint64(depositValue),
|
|
|
|
depositInput.ProofOfPossession,
|
|
|
|
depositInput.WithdrawalCredentialsHash32,
|
|
|
|
depositInput.RandaoCommitmentHash32,
|
|
|
|
depositInput.PocCommitment,
|
2018-12-31 07:40:14 +00:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("could not process validator deposit: %v", err)
|
|
|
|
}
|
2019-01-05 06:39:07 +00:00
|
|
|
}
|
|
|
|
for validatorIndex := range state.ValidatorRegistry {
|
|
|
|
if v.EffectiveBalance(state, uint32(validatorIndex)) ==
|
2018-12-31 07:40:14 +00:00
|
|
|
params.BeaconConfig().MaxDepositInGwei {
|
2019-01-05 06:39:07 +00:00
|
|
|
state, err = v.ActivateValidator(state, uint32(validatorIndex), true)
|
2018-12-31 07:40:14 +00:00
|
|
|
if err != nil {
|
2019-01-05 06:39:07 +00:00
|
|
|
return nil, fmt.Errorf("could not activate validator: %v", err)
|
2018-12-31 07:40:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set initial committee shuffling.
|
|
|
|
initialShuffling, err := v.ShuffleValidatorRegistryToCommittees(
|
|
|
|
params.BeaconConfig().ZeroHash,
|
|
|
|
state.ValidatorRegistry,
|
|
|
|
0,
|
2019-01-05 06:39:07 +00:00
|
|
|
params.BeaconConfig().GenesisSlot,
|
2018-12-31 07:40:14 +00:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("could not shuffle initial committee: %v", err)
|
|
|
|
}
|
|
|
|
state.ShardAndCommitteesAtSlots = append(initialShuffling, initialShuffling...)
|
|
|
|
|
|
|
|
return state, nil
|
|
|
|
}
|
|
|
|
|
2018-12-25 06:47:07 +00:00
|
|
|
// Hash the beacon state data structure.
|
|
|
|
func Hash(state *pb.BeaconState) ([32]byte, error) {
|
|
|
|
data, err := proto.Marshal(state)
|
|
|
|
if err != nil {
|
|
|
|
return [32]byte{}, fmt.Errorf("could not marshal beacon state: %v", err)
|
|
|
|
}
|
|
|
|
return hashutil.Hash(data), nil
|
|
|
|
}
|
|
|
|
|
2018-12-23 22:51:04 +00:00
|
|
|
// 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) {
|
2019-01-05 03:58:19 +00:00
|
|
|
distance := block.Slot - parentSlot
|
|
|
|
existing := state.LatestBlockRootHash32S
|
2018-12-23 22:51:04 +00:00
|
|
|
update := existing[distance:]
|
2019-01-06 04:36:05 +00:00
|
|
|
for len(update) < 2*int(params.BeaconConfig().EpochLength) {
|
2019-01-05 03:58:19 +00:00
|
|
|
update = append(update, block.ParentRootHash32)
|
2018-12-23 22:51:04 +00:00
|
|
|
}
|
|
|
|
return update, nil
|
|
|
|
}
|