2020-07-06 22:27:42 +00:00
|
|
|
package blocks
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2020-09-01 01:29:27 +00:00
|
|
|
"context"
|
2020-07-06 22:27:42 +00:00
|
|
|
"fmt"
|
|
|
|
|
2021-04-15 13:58:54 +00:00
|
|
|
types "github.com/prysmaticlabs/eth2-types"
|
2020-07-06 22:27:42 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
2021-03-08 22:37:33 +00:00
|
|
|
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
2021-06-02 23:49:52 +00:00
|
|
|
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
2021-05-26 16:19:54 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/interfaces"
|
2020-07-06 22:27:42 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/params"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ProcessBlockHeader validates a block by its header.
|
|
|
|
//
|
|
|
|
// Spec pseudocode definition:
|
|
|
|
//
|
|
|
|
// def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
|
|
|
|
// # Verify that the slots match
|
|
|
|
// assert block.slot == state.slot
|
2021-04-13 05:35:22 +00:00
|
|
|
// # Verify that the block is newer than latest block header
|
|
|
|
// assert block.slot > state.latest_block_header.slot
|
|
|
|
// # Verify that proposer index is the correct index
|
2020-07-06 22:27:42 +00:00
|
|
|
// assert block.proposer_index == get_beacon_proposer_index(state)
|
|
|
|
// # Verify that the parent matches
|
|
|
|
// assert block.parent_root == hash_tree_root(state.latest_block_header)
|
2021-04-13 05:35:22 +00:00
|
|
|
// # Cache current block as the new latest block
|
2020-07-06 22:27:42 +00:00
|
|
|
// state.latest_block_header = BeaconBlockHeader(
|
|
|
|
// slot=block.slot,
|
2021-04-13 05:35:22 +00:00
|
|
|
// proposer_index=block.proposer_index,
|
2020-07-06 22:27:42 +00:00
|
|
|
// parent_root=block.parent_root,
|
2021-04-13 05:35:22 +00:00
|
|
|
// state_root=Bytes32(), # Overwritten in the next process_slot call
|
2020-07-06 22:27:42 +00:00
|
|
|
// body_root=hash_tree_root(block.body),
|
|
|
|
// )
|
2021-04-13 05:35:22 +00:00
|
|
|
//
|
2020-07-06 22:27:42 +00:00
|
|
|
// # Verify proposer is not slashed
|
2021-04-13 05:35:22 +00:00
|
|
|
// proposer = state.validators[block.proposer_index]
|
2020-07-06 22:27:42 +00:00
|
|
|
// assert not proposer.slashed
|
|
|
|
func ProcessBlockHeader(
|
2020-10-12 08:11:05 +00:00
|
|
|
_ context.Context,
|
2021-03-08 22:37:33 +00:00
|
|
|
beaconState iface.BeaconState,
|
2021-05-26 16:19:54 +00:00
|
|
|
block interfaces.SignedBeaconBlock,
|
2021-03-08 22:37:33 +00:00
|
|
|
) (iface.BeaconState, error) {
|
2021-04-15 13:58:54 +00:00
|
|
|
if err := helpers.VerifyNilBeaconBlock(block); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-05-26 16:19:54 +00:00
|
|
|
bodyRoot, err := block.Block().Body().HashTreeRoot()
|
2021-04-15 13:58:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-05-26 16:19:54 +00:00
|
|
|
beaconState, err = ProcessBlockHeaderNoVerify(beaconState, block.Block().Slot(), block.Block().ProposerIndex(), block.Block().ParentRoot(), bodyRoot[:])
|
2020-07-06 22:27:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify proposer signature.
|
2021-05-26 16:19:54 +00:00
|
|
|
if err := VerifyBlockSignature(beaconState, block.Block().ProposerIndex(), block.Signature(), block.Block().HashTreeRoot); err != nil {
|
2020-07-06 22:27:42 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return beaconState, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ProcessBlockHeaderNoVerify validates a block by its header but skips proposer
|
|
|
|
// signature verification.
|
|
|
|
//
|
|
|
|
// WARNING: This method does not verify proposer signature. This is used for proposer to compute state root
|
|
|
|
// using a unsigned block.
|
|
|
|
//
|
|
|
|
// Spec pseudocode definition:
|
|
|
|
// def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
|
|
|
|
// # Verify that the slots match
|
|
|
|
// assert block.slot == state.slot
|
2021-04-13 05:35:22 +00:00
|
|
|
// # Verify that the block is newer than latest block header
|
|
|
|
// assert block.slot > state.latest_block_header.slot
|
|
|
|
// # Verify that proposer index is the correct index
|
2020-07-06 22:27:42 +00:00
|
|
|
// assert block.proposer_index == get_beacon_proposer_index(state)
|
|
|
|
// # Verify that the parent matches
|
|
|
|
// assert block.parent_root == hash_tree_root(state.latest_block_header)
|
2021-04-13 05:35:22 +00:00
|
|
|
// # Cache current block as the new latest block
|
2020-07-06 22:27:42 +00:00
|
|
|
// state.latest_block_header = BeaconBlockHeader(
|
|
|
|
// slot=block.slot,
|
2021-04-13 05:35:22 +00:00
|
|
|
// proposer_index=block.proposer_index,
|
2020-07-06 22:27:42 +00:00
|
|
|
// parent_root=block.parent_root,
|
2021-04-13 05:35:22 +00:00
|
|
|
// state_root=Bytes32(), # Overwritten in the next process_slot call
|
2020-07-06 22:27:42 +00:00
|
|
|
// body_root=hash_tree_root(block.body),
|
|
|
|
// )
|
2021-04-13 05:35:22 +00:00
|
|
|
//
|
2020-07-06 22:27:42 +00:00
|
|
|
// # Verify proposer is not slashed
|
2021-04-13 05:35:22 +00:00
|
|
|
// proposer = state.validators[block.proposer_index]
|
2020-07-06 22:27:42 +00:00
|
|
|
// assert not proposer.slashed
|
|
|
|
func ProcessBlockHeaderNoVerify(
|
2021-03-08 22:37:33 +00:00
|
|
|
beaconState iface.BeaconState,
|
2021-04-15 13:58:54 +00:00
|
|
|
slot types.Slot, proposerIndex types.ValidatorIndex,
|
|
|
|
parentRoot, bodyRoot []byte,
|
2021-03-08 22:37:33 +00:00
|
|
|
) (iface.BeaconState, error) {
|
2021-04-15 13:58:54 +00:00
|
|
|
if beaconState.Slot() != slot {
|
|
|
|
return nil, fmt.Errorf("state slot: %d is different than block slot: %d", beaconState.Slot(), slot)
|
2020-07-06 22:27:42 +00:00
|
|
|
}
|
|
|
|
idx, err := helpers.BeaconProposerIndex(beaconState)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-04-15 13:58:54 +00:00
|
|
|
if proposerIndex != idx {
|
|
|
|
return nil, fmt.Errorf("proposer index: %d is different than calculated: %d", proposerIndex, idx)
|
2020-07-06 22:27:42 +00:00
|
|
|
}
|
|
|
|
parentHeader := beaconState.LatestBlockHeader()
|
2021-04-15 13:58:54 +00:00
|
|
|
if parentHeader.Slot >= slot {
|
|
|
|
return nil, fmt.Errorf("block.Slot %d must be greater than state.LatestBlockHeader.Slot %d", slot, parentHeader.Slot)
|
2020-07-06 22:27:42 +00:00
|
|
|
}
|
2021-04-15 13:58:54 +00:00
|
|
|
parentHeaderRoot, err := parentHeader.HashTreeRoot()
|
2020-07-06 22:27:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-04-15 13:58:54 +00:00
|
|
|
if !bytes.Equal(parentRoot, parentHeaderRoot[:]) {
|
2020-07-06 22:27:42 +00:00
|
|
|
return nil, fmt.Errorf(
|
|
|
|
"parent root %#x does not match the latest block header signing root in state %#x",
|
2021-04-15 13:58:54 +00:00
|
|
|
parentRoot, parentHeaderRoot[:])
|
2020-07-06 22:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
proposer, err := beaconState.ValidatorAtIndexReadOnly(idx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if proposer.Slashed() {
|
|
|
|
return nil, fmt.Errorf("proposer at index %d was previously slashed", idx)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := beaconState.SetLatestBlockHeader(ðpb.BeaconBlockHeader{
|
2021-04-15 13:58:54 +00:00
|
|
|
Slot: slot,
|
|
|
|
ProposerIndex: proposerIndex,
|
|
|
|
ParentRoot: parentRoot,
|
2020-07-06 22:27:42 +00:00
|
|
|
StateRoot: params.BeaconConfig().ZeroHash[:],
|
2021-04-15 13:58:54 +00:00
|
|
|
BodyRoot: bodyRoot,
|
2020-07-06 22:27:42 +00:00
|
|
|
}); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return beaconState, nil
|
|
|
|
}
|