mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-11 12:10:05 +00:00
186 lines
6.2 KiB
Go
186 lines
6.2 KiB
Go
package state
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/types"
|
|
v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
|
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
|
"github.com/prysmaticlabs/prysm/shared/bitutil"
|
|
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
|
"github.com/prysmaticlabs/prysm/shared/params"
|
|
)
|
|
|
|
// IsValidBlock verifies a block is valid according to the ETH 2.0 specification for
|
|
// validity conditions taking into consideration attestation processing and more.
|
|
// TODO(#781): Refactor with the new spec validity conditions.
|
|
func IsValidBlock(
|
|
block *types.Block,
|
|
beaconState *types.BeaconState,
|
|
parentSlot uint64,
|
|
genesisTime time.Time,
|
|
isInChain func(blockHash [32]byte) bool,
|
|
) error {
|
|
_, err := block.Hash()
|
|
if err != nil {
|
|
return fmt.Errorf("could not hash incoming block: %v", err)
|
|
}
|
|
|
|
if block.SlotNumber() == 0 {
|
|
return errors.New("cannot process a genesis block: received block with slot 0")
|
|
}
|
|
|
|
if !block.IsSlotValid(genesisTime) {
|
|
return fmt.Errorf("slot of block is too high: %d", block.SlotNumber())
|
|
}
|
|
|
|
if err := doesParentProposerExist(block, beaconState, parentSlot); err != nil {
|
|
return fmt.Errorf("could not get proposer index: %v", err)
|
|
}
|
|
|
|
for _, attestation := range block.Attestations() {
|
|
if err := isBlockAttestationValid(block, attestation, beaconState, parentSlot, isInChain); err != nil {
|
|
return fmt.Errorf("invalid block attestation: %v", err)
|
|
}
|
|
}
|
|
|
|
_, proposerIndex, err := v.ProposerShardAndIndex(
|
|
beaconState.ShardAndCommitteesForSlots(),
|
|
beaconState.LastStateRecalculationSlot(),
|
|
block.SlotNumber(),
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("could not get proposer index: %v", err)
|
|
}
|
|
|
|
stateProposerRandaoSeed := beaconState.ValidatorRegistry()[proposerIndex].RandaoCommitmentHash32
|
|
blockRandaoRevealHash32 := block.RandaoRevealHash32()
|
|
|
|
// If this is a block created by the simulator service (while in development
|
|
// mode), we skip the RANDAO validation condition.
|
|
isSimulatedBlock := bytes.Equal(blockRandaoRevealHash32[:], params.BeaconConfig().SimulatedBlockRandao[:])
|
|
if !isSimulatedBlock && !block.IsRandaoValid(stateProposerRandaoSeed) {
|
|
return fmt.Errorf(
|
|
"pre-image of %#x is %#x, Got: %#x",
|
|
blockRandaoRevealHash32[:],
|
|
hashutil.Hash(blockRandaoRevealHash32[:]),
|
|
stateProposerRandaoSeed,
|
|
)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// doesParentProposerExist checks that the proposer from the parent slot is included in the first
|
|
// aggregated attestation object
|
|
func doesParentProposerExist(block *types.Block, beaconState *types.BeaconState, parentSlot uint64) error {
|
|
_, parentProposerIndex, err := v.ProposerShardAndIndex(
|
|
beaconState.ShardAndCommitteesForSlots(),
|
|
beaconState.LastStateRecalculationSlot(),
|
|
parentSlot,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Verifies the attester bitfield to check if the proposer index is in the first included one.
|
|
if isBitSet, err := bitutil.CheckBit(block.Attestations()[0].AttesterBitfield, int(parentProposerIndex)); !isBitSet {
|
|
return fmt.Errorf("could not locate proposer in the first attestation of AttestionRecord: %v", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// isBlockAttestationValid verifies a block's attestations pass validity conditions.
|
|
// TODO(#781): Refactor with the new spec attestation checking conditions.
|
|
func isBlockAttestationValid(
|
|
block *types.Block,
|
|
attestation *pb.AggregatedAttestation,
|
|
beaconState *types.BeaconState,
|
|
parentSlot uint64,
|
|
isInChain func(blockHash [32]byte) bool,
|
|
) error {
|
|
// Validate attestation's slot number has is within range of incoming block number.
|
|
if err := isAttestationSlotNumberValid(attestation.Slot, parentSlot); err != nil {
|
|
return fmt.Errorf("invalid attestation slot %d: %v", attestation.Slot, err)
|
|
}
|
|
|
|
if attestation.JustifiedSlot > beaconState.LastJustifiedSlot() {
|
|
return fmt.Errorf(
|
|
"attestation's justified slot has to be <= the state's last justified slot: found: %d. want <=: %d",
|
|
attestation.JustifiedSlot,
|
|
beaconState.LastJustifiedSlot(),
|
|
)
|
|
}
|
|
|
|
hash := [32]byte{}
|
|
copy(hash[:], attestation.JustifiedBlockHash)
|
|
if !isInChain(hash) {
|
|
return fmt.Errorf(
|
|
"the attestation's justifed block hash not found in current chain: justified block hash: 0x%x",
|
|
attestation.JustifiedBlockHash,
|
|
)
|
|
}
|
|
|
|
// Get all the block hashes up to cycle length.
|
|
parentHashes, err := beaconState.SignedParentHashes(block, attestation)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to get signed parent hashes: %v", err)
|
|
}
|
|
|
|
shardCommittees, err := v.GetShardAndCommitteesForSlot(
|
|
beaconState.ShardAndCommitteesForSlots(),
|
|
beaconState.LastStateRecalculationSlot(),
|
|
attestation.Slot,
|
|
)
|
|
attesterIndices, err := v.AttesterIndices(shardCommittees, attestation)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to get validator committee: %v", err)
|
|
}
|
|
|
|
// Verify attester bitfields matches crystallized state's prev computed bitfield.
|
|
if !v.AreAttesterBitfieldsValid(attestation, attesterIndices) {
|
|
return fmt.Errorf("unable to match attester bitfield with shard and committee bitfield")
|
|
}
|
|
|
|
// TODO(#258): Add coverage for determining fork version for an attestation.
|
|
forkData := beaconState.ForkData()
|
|
forkVersion := forkData.PostForkVersion
|
|
if attestation.Slot < forkData.ForkSlot {
|
|
forkVersion = forkData.PreForkVersion
|
|
}
|
|
|
|
// TODO(#258): Generate validators aggregated pub key.
|
|
attestationMsg := types.AttestationMsg(
|
|
parentHashes,
|
|
attestation.ShardBlockHash,
|
|
attestation.Slot,
|
|
attestation.Shard,
|
|
attestation.JustifiedSlot,
|
|
forkVersion,
|
|
)
|
|
_ = attestationMsg
|
|
|
|
// TODO(#258): Verify msgHash against aggregated pub key and aggregated signature.
|
|
return nil
|
|
}
|
|
|
|
func isAttestationSlotNumberValid(attestationSlot uint64, parentSlot uint64) error {
|
|
if parentSlot != 0 && attestationSlot > parentSlot {
|
|
return fmt.Errorf(
|
|
"attestation slot number higher than parent block's slot number: found: %d, needed < %d",
|
|
attestationSlot,
|
|
parentSlot,
|
|
)
|
|
}
|
|
if parentSlot >= params.BeaconConfig().CycleLength-1 && attestationSlot < parentSlot-params.BeaconConfig().CycleLength+1 {
|
|
return fmt.Errorf(
|
|
"attestation slot number lower than parent block's slot number by one CycleLength: found: %d, needed > %d",
|
|
attestationSlot,
|
|
parentSlot-params.BeaconConfig().CycleLength+1,
|
|
)
|
|
}
|
|
return nil
|
|
}
|