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

117 lines
3.6 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"
)
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 (s *StateTransistor) ProcessBlockHeader(block *cltypes.BeaconBlock) error {
if !s.noValidate {
if block.Slot != s.state.Slot() {
return fmt.Errorf("state slot: %d, not equal to block slot: %d", s.state.Slot(), block.Slot)
}
if block.Slot <= s.state.LatestBlockHeader().Slot {
return fmt.Errorf("slock slot: %d, not greater than latest block slot: %d", block.Slot, s.state.LatestBlockHeader().Slot)
}
propInd, err := s.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 := s.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)
}
s.state.SetLatestBlockHeader(&cltypes.BeaconBlockHeader{
Slot: block.Slot,
ProposerIndex: block.ProposerIndex,
ParentRoot: block.ParentRoot,
BodyRoot: bodyRoot,
})
proposer, err := s.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 (s *StateTransistor) ProcessRandao(randao [96]byte, proposerIndex uint64) error {
epoch := s.state.Epoch()
proposer, err := s.state.ValidatorAt(int(proposerIndex))
if err != nil {
return err
}
if !s.noValidate {
domain, err := s.state.GetDomain(s.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 := s.state.GetRandaoMixes(epoch)
randaoHash := utils.Keccak256(randao[:])
mix := [32]byte{}
for i := range mix {
mix[i] = randaoMixes[i] ^ randaoHash[i]
}
s.state.SetRandaoMixAt(int(epoch%s.beaconConfig.EpochsPerHistoricalVector), mix)
return nil
}
func (s *StateTransistor) ProcessEth1Data(eth1Data *cltypes.Eth1Data) error {
s.state.AddEth1DataVote(eth1Data)
newVotes := s.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) > s.beaconConfig.EpochsPerEth1VotingPeriod*s.beaconConfig.SlotsPerEpoch {
s.state.SetEth1Data(eth1Data)
}
return nil
}