erigon-pulse/cmd/erigon-cl/core/transition/processing.go

118 lines
3.8 KiB
Go

package transition
import (
"encoding/binary"
"fmt"
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/Giulio2002/bls"
"github.com/ledgerwatch/erigon/cl/cltypes"
"github.com/ledgerwatch/erigon/cl/utils"
"github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state"
)
func computeSigningRootEpoch(epoch uint64, domain []byte) (libcommon.Hash, error) {
b := make([]byte, 32)
binary.LittleEndian.PutUint64(b, epoch)
return utils.Keccak256(b, domain), nil
}
func ProcessBlockHeader(state *state.BeaconState, block *cltypes.BeaconBlock, fullValidation bool) error {
if fullValidation {
if block.Slot != state.Slot() {
return fmt.Errorf("state slot: %d, not equal to block slot: %d", state.Slot(), block.Slot)
}
if block.Slot <= state.LatestBlockHeader().Slot {
return fmt.Errorf("slock slot: %d, not greater than latest block slot: %d", block.Slot, state.LatestBlockHeader().Slot)
}
propInd, err := state.GetBeaconProposerIndex()
if err != nil {
return fmt.Errorf("error in GetBeaconProposerIndex: %v", err)
}
if block.ProposerIndex != propInd {
return fmt.Errorf("block proposer index: %d, does not match beacon proposer index: %d", block.ProposerIndex, propInd)
}
latestRoot, err := state.LatestBlockHeader().HashSSZ()
if err != nil {
return fmt.Errorf("unable to hash tree root of latest block header: %v", err)
}
if block.ParentRoot != latestRoot {
return fmt.Errorf("block parent root: %x, does not match latest block root: %x", block.ParentRoot, latestRoot)
}
}
bodyRoot, err := block.Body.HashSSZ()
if err != nil {
return fmt.Errorf("unable to hash tree root of block body: %v", err)
}
state.SetLatestBlockHeader(&cltypes.BeaconBlockHeader{
Slot: block.Slot,
ProposerIndex: block.ProposerIndex,
ParentRoot: block.ParentRoot,
BodyRoot: bodyRoot,
})
proposer, err := state.ValidatorAt(int(block.ProposerIndex))
if err != nil {
return err
}
if proposer.Slashed {
return fmt.Errorf("proposer: %d is slashed", block.ProposerIndex)
}
return nil
}
func ProcessRandao(state *state.BeaconState, randao [96]byte, proposerIndex uint64, fullValidation bool) error {
epoch := state.Epoch()
proposer, err := state.ValidatorAt(int(proposerIndex))
if err != nil {
return err
}
if fullValidation {
domain, err := state.GetDomain(state.BeaconConfig().DomainRandao, epoch)
if err != nil {
return fmt.Errorf("ProcessRandao: unable to get domain: %v", err)
}
signingRoot, err := computeSigningRootEpoch(epoch, domain)
if err != nil {
return fmt.Errorf("ProcessRandao: unable to compute signing root: %v", err)
}
valid, err := bls.Verify(randao[:], signingRoot[:], proposer.PublicKey[:])
if err != nil {
return fmt.Errorf("ProcessRandao: unable to verify public key: %x, with signing root: %x, and signature: %x, %v", proposer.PublicKey[:], signingRoot[:], randao[:], err)
}
if !valid {
return fmt.Errorf("ProcessRandao: invalid signature: public key: %x, signing root: %x, signature: %x", proposer.PublicKey[:], signingRoot[:], randao[:])
}
}
randaoMixes := state.GetRandaoMixes(epoch)
randaoHash := utils.Keccak256(randao[:])
mix := [32]byte{}
for i := range mix {
mix[i] = randaoMixes[i] ^ randaoHash[i]
}
state.SetRandaoMixAt(int(epoch%state.BeaconConfig().EpochsPerHistoricalVector), mix)
return nil
}
func ProcessEth1Data(state *state.BeaconState, eth1Data *cltypes.Eth1Data) error {
state.AddEth1DataVote(eth1Data)
newVotes := state.Eth1DataVotes()
// Count how many times body.Eth1Data appears in the votes.
numVotes := 0
for i := 0; i < len(newVotes); i++ {
if eth1Data.Equal(newVotes[i]) {
numVotes += 1
}
}
if uint64(numVotes*2) > state.BeaconConfig().EpochsPerEth1VotingPeriod*state.BeaconConfig().SlotsPerEpoch {
state.SetEth1Data(eth1Data)
}
return nil
}