prysm-pulse/testing/util/capella_block.go
terence 5a66807989
Update to V5 (#13622)
* First take at updating everything to v5

* Patch gRPC gateway to use prysm v5

Fix patch

* Update go ssz

---------

Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>
2024-02-15 05:46:47 +00:00

235 lines
7.4 KiB
Go

package util
import (
"context"
"fmt"
"github.com/pkg/errors"
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/signing"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/crypto/bls"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
v1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/time/slots"
)
// GenerateFullBlockCapella generates a fully valid Capella block with the requested parameters.
// Use BlockGenConfig to declare the conditions you would like the block generated under.
// This function modifies the passed state as follows:
func GenerateFullBlockCapella(
bState state.BeaconState,
privs []bls.SecretKey,
conf *BlockGenConfig,
slot primitives.Slot,
) (*ethpb.SignedBeaconBlockCapella, error) {
ctx := context.Background()
currentSlot := bState.Slot()
if currentSlot > slot {
return nil, fmt.Errorf("current slot in state is larger than given slot. %d > %d", currentSlot, slot)
}
bState = bState.Copy()
if conf == nil {
conf = &BlockGenConfig{}
}
var err error
var pSlashings []*ethpb.ProposerSlashing
numToGen := conf.NumProposerSlashings
if numToGen > 0 {
pSlashings, err = generateProposerSlashings(bState, privs, numToGen)
if err != nil {
return nil, errors.Wrapf(err, "failed generating %d proposer slashings:", numToGen)
}
}
numToGen = conf.NumAttesterSlashings
var aSlashings []*ethpb.AttesterSlashing
if numToGen > 0 {
aSlashings, err = generateAttesterSlashings(bState, privs, numToGen)
if err != nil {
return nil, errors.Wrapf(err, "failed generating %d attester slashings:", numToGen)
}
}
numToGen = conf.NumAttestations
var atts []*ethpb.Attestation
if numToGen > 0 {
atts, err = GenerateAttestations(bState, privs, numToGen, slot, false)
if err != nil {
return nil, errors.Wrapf(err, "failed generating %d attestations:", numToGen)
}
}
numToGen = conf.NumDeposits
var newDeposits []*ethpb.Deposit
eth1Data := bState.Eth1Data()
if numToGen > 0 {
newDeposits, eth1Data, err = generateDepositsAndEth1Data(bState, numToGen)
if err != nil {
return nil, errors.Wrapf(err, "failed generating %d deposits:", numToGen)
}
}
numToGen = conf.NumVoluntaryExits
var exits []*ethpb.SignedVoluntaryExit
if numToGen > 0 {
exits, err = generateVoluntaryExits(bState, privs, numToGen)
if err != nil {
return nil, errors.Wrapf(err, "failed generating %d attester slashings:", numToGen)
}
}
numToGen = conf.NumTransactions
newTransactions := make([][]byte, numToGen)
for i := uint64(0); i < numToGen; i++ {
newTransactions[i] = bytesutil.Uint64ToBytesLittleEndian(i)
}
newWithdrawals := make([]*v1.Withdrawal, 0)
random, err := helpers.RandaoMix(bState, time.CurrentEpoch(bState))
if err != nil {
return nil, errors.Wrap(err, "could not process randao mix")
}
timestamp, err := slots.ToTime(bState.GenesisTime(), slot)
if err != nil {
return nil, errors.Wrap(err, "could not get current timestamp")
}
stCopy := bState.Copy()
stCopy, err = transition.ProcessSlots(context.Background(), stCopy, slot)
if err != nil {
return nil, err
}
parentExecution, err := stCopy.LatestExecutionPayloadHeader()
if err != nil {
return nil, err
}
blockHash := indexToHash(uint64(slot))
newExecutionPayloadCapella := &v1.ExecutionPayloadCapella{
ParentHash: parentExecution.BlockHash(),
FeeRecipient: make([]byte, 20),
StateRoot: params.BeaconConfig().ZeroHash[:],
ReceiptsRoot: params.BeaconConfig().ZeroHash[:],
LogsBloom: make([]byte, 256),
PrevRandao: random,
BlockNumber: uint64(slot),
ExtraData: params.BeaconConfig().ZeroHash[:],
BaseFeePerGas: params.BeaconConfig().ZeroHash[:],
BlockHash: blockHash[:],
Timestamp: uint64(timestamp.Unix()),
Transactions: newTransactions,
Withdrawals: newWithdrawals,
}
var syncCommitteeBits []byte
currSize := new(ethpb.SyncAggregate).SyncCommitteeBits.Len()
switch currSize {
case 512:
syncCommitteeBits = bitfield.NewBitvector512()
case 32:
syncCommitteeBits = bitfield.NewBitvector32()
default:
return nil, errors.New("invalid bit vector size")
}
newSyncAggregate := &ethpb.SyncAggregate{
SyncCommitteeBits: syncCommitteeBits,
SyncCommitteeSignature: append([]byte{0xC0}, make([]byte, 95)...),
}
newHeader := bState.LatestBlockHeader()
prevStateRoot, err := bState.HashTreeRoot(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not hash state")
}
newHeader.StateRoot = prevStateRoot[:]
parentRoot, err := newHeader.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not hash the new header")
}
if slot == currentSlot {
slot = currentSlot + 1
}
reveal, err := RandaoReveal(stCopy, time.CurrentEpoch(stCopy), privs)
if err != nil {
return nil, errors.Wrap(err, "could not compute randao reveal")
}
idx, err := helpers.BeaconProposerIndex(ctx, stCopy)
if err != nil {
return nil, errors.Wrap(err, "could not compute beacon proposer index")
}
changes := make([]*ethpb.SignedBLSToExecutionChange, conf.NumBLSChanges)
for i := uint64(0); i < conf.NumBLSChanges; i++ {
changes[i], err = GenerateBLSToExecutionChange(bState, privs[i+1], primitives.ValidatorIndex(i))
if err != nil {
return nil, err
}
}
block := &ethpb.BeaconBlockCapella{
Slot: slot,
ParentRoot: parentRoot[:],
ProposerIndex: idx,
Body: &ethpb.BeaconBlockBodyCapella{
Eth1Data: eth1Data,
RandaoReveal: reveal,
ProposerSlashings: pSlashings,
AttesterSlashings: aSlashings,
Attestations: atts,
VoluntaryExits: exits,
Deposits: newDeposits,
Graffiti: make([]byte, fieldparams.RootLength),
SyncAggregate: newSyncAggregate,
ExecutionPayload: newExecutionPayloadCapella,
BlsToExecutionChanges: changes,
},
}
// The fork can change after processing the state
signature, err := BlockSignature(bState, block, privs)
if err != nil {
return nil, errors.Wrap(err, "could not compute block signature")
}
return &ethpb.SignedBeaconBlockCapella{Block: block, Signature: signature.Marshal()}, nil
}
// GenerateBLSToExecutionChange generates a valid bls to exec changae for validator `val` and its private key `priv` with the given beacon state `st`.
func GenerateBLSToExecutionChange(st state.BeaconState, priv bls.SecretKey, val primitives.ValidatorIndex) (*ethpb.SignedBLSToExecutionChange, error) {
cred := indexToHash(uint64(val))
pubkey := priv.PublicKey().Marshal()
message := &ethpb.BLSToExecutionChange{
ToExecutionAddress: cred[12:],
ValidatorIndex: val,
FromBlsPubkey: pubkey,
}
c := params.BeaconConfig()
domain, err := signing.ComputeDomain(c.DomainBLSToExecutionChange, c.GenesisForkVersion, st.GenesisValidatorsRoot())
if err != nil {
return nil, err
}
sr, err := signing.ComputeSigningRoot(message, domain)
if err != nil {
return nil, err
}
signature := priv.Sign(sr[:]).Marshal()
return &ethpb.SignedBLSToExecutionChange{
Message: message,
Signature: signature,
}, nil
}