Skip to content

Commit

Permalink
added support for Capella beacon blocks (erigontech#6665)
Browse files Browse the repository at this point in the history
  • Loading branch information
Giulio2002 authored Jan 22, 2023
1 parent 5351e23 commit 20a4ae4
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 56 deletions.
18 changes: 4 additions & 14 deletions cl/clparams/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,15 +211,6 @@ var CheckpointSyncEndpoints = map[NetworkType][]string{

// BeaconChainConfig contains constant configs for node to participate in beacon chain.
type BeaconChainConfig struct {
// Constants (non-configurable)
GenesisSlot uint64 `yaml:"GENESIS_SLOT"` // GenesisSlot represents the first canonical slot number of the beacon chain.
GenesisEpoch uint64 `yaml:"GENESIS_EPOCH"` // GenesisEpoch represents the first canonical epoch number of the beacon chain.
FarFutureEpoch uint64 `yaml:"FAR_FUTURE_EPOCH"` // FarFutureEpoch represents a epoch extremely far away in the future used as the default penalization epoch for validators.
FarFutureSlot uint64 `yaml:"FAR_FUTURE_SLOT"` // FarFutureSlot represents a slot extremely far away in the future.
BaseRewardsPerEpoch uint64 `yaml:"BASE_REWARDS_PER_EPOCH"` // BaseRewardsPerEpoch is used to calculate the per epoch rewards.
DepositContractTreeDepth uint64 `yaml:"DEPOSIT_CONTRACT_TREE_DEPTH"` // DepositContractTreeDepth depth of the Merkle trie of deposits in the validator deposit contract on the PoW chain.
JustificationBitsLength uint64 `yaml:"JUSTIFICATION_BITS_LENGTH"` // JustificationBitsLength defines number of epochs to track when implementing k-finality in Casper FFG.

// Misc constants.
PresetBase string `yaml:"PRESET_BASE" spec:"true"` // PresetBase represents the underlying spec preset this config is based on.
ConfigName string `yaml:"CONFIG_NAME" spec:"true"` // ConfigName for allowing an easy human-readable way of knowing what chain is being used.
Expand Down Expand Up @@ -417,7 +408,7 @@ func toBytes4(in []byte) (ret [4]byte) {

func configForkSchedule(b *BeaconChainConfig) map[[VersionLength]byte]uint64 {
fvs := map[[VersionLength]byte]uint64{}
fvs[toBytes4(b.GenesisForkVersion)] = b.GenesisEpoch
fvs[toBytes4(b.GenesisForkVersion)] = 0
fvs[toBytes4(b.AltairForkVersion)] = b.AltairForkEpoch
fvs[toBytes4(b.BellatrixForkVersion)] = b.BellatrixForkEpoch
return fvs
Expand All @@ -433,11 +424,11 @@ func configForkNames(b *BeaconChainConfig) map[[VersionLength]byte]string {

var MainnetBeaconConfig BeaconChainConfig = BeaconChainConfig{
// Constants (Non-configurable)
FarFutureEpoch: math.MaxUint64,
/*FarFutureEpoch: math.MaxUint64,
FarFutureSlot: math.MaxUint64,
BaseRewardsPerEpoch: 4,
DepositContractTreeDepth: 32,
GenesisDelay: 604800, // 1 week.
DepositContractTreeDepth: 32,*/
GenesisDelay: 604800, // 1 week.

// Misc constant.
TargetCommitteeSize: 128,
Expand Down Expand Up @@ -564,7 +555,6 @@ var MainnetBeaconConfig BeaconChainConfig = BeaconChainConfig{
SafetyDecay: 10,

// Fork related values.
GenesisEpoch: 0,
GenesisForkVersion: []byte{0, 0, 0, 0},
AltairForkVersion: []byte{1, 0, 0, 0},
AltairForkEpoch: 74240,
Expand Down
60 changes: 54 additions & 6 deletions cl/cltypes/beacon_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,13 @@ const (
MaxAttestations = 128
MaxDeposits = 16
MaxVoluntaryExits = 16
MaxExecutionChanges = 16
)

func getBeaconBlockMinimumSize(v clparams.StateVersion) (size uint32) {
switch v {
case clparams.CapellaVersion:
size = 388
case clparams.BellatrixVersion:
size = 384
case clparams.AltairVersion:
Expand Down Expand Up @@ -96,6 +99,8 @@ type BeaconBody struct {
SyncAggregate *SyncAggregate
// Data related to crosslink records and executing operations on the Ethereum 2.0 chain
ExecutionPayload *Eth1Block
// Withdrawals Diffs for Execution Layer
ExecutionChanges []*SignedBLSToExecutionChange
// The version of the beacon chain
Version clparams.StateVersion
}
Expand Down Expand Up @@ -151,6 +156,10 @@ func (b *BeaconBody) EncodeSSZ(dst []byte) ([]byte, error) {
}
if b.Version >= clparams.BellatrixVersion {
buf = append(buf, ssz_utils.OffsetSSZ(offset)...)
offset += uint32(b.ExecutionPayload.EncodingSizeSSZ(b.Version))
}
if b.Version >= clparams.CapellaVersion {
buf = append(buf, ssz_utils.OffsetSSZ(offset)...)
}
// Now start encoding the rest of the fields.
if len(b.AttesterSlashings) > MaxAttesterSlashings {
Expand All @@ -168,6 +177,9 @@ func (b *BeaconBody) EncodeSSZ(dst []byte) ([]byte, error) {
if len(b.VoluntaryExits) > MaxVoluntaryExits {
return nil, fmt.Errorf("Encode(SSZ): too many attestations")
}
if len(b.ExecutionChanges) > MaxExecutionChanges {
return nil, fmt.Errorf("Encode(SSZ): too many changes")
}
// Write proposer slashings
for _, proposerSlashing := range b.ProposerSlashings {
if buf, err = proposerSlashing.EncodeSSZ(buf); err != nil {
Expand Down Expand Up @@ -209,11 +221,19 @@ func (b *BeaconBody) EncodeSSZ(dst []byte) ([]byte, error) {
}

if b.Version >= clparams.BellatrixVersion {
buf, err = b.ExecutionPayload.EncodeSSZ(buf)
buf, err = b.ExecutionPayload.EncodeSSZ(buf, b.Version)
if err != nil {
return nil, err
}
}

if b.Version >= clparams.CapellaVersion {
for _, change := range b.ExecutionChanges {
if buf, err = change.EncodeSSZ(buf); err != nil {
return nil, err
}
}
}
return buf, nil
}

Expand All @@ -239,9 +259,14 @@ func (b *BeaconBody) EncodingSizeSSZ() (size int) {
if b.ExecutionPayload == nil {
b.ExecutionPayload = new(Eth1Block)
}
size += b.ExecutionPayload.EncodingSizeSSZ()
size += b.ExecutionPayload.EncodingSizeSSZ(b.Version)
}

if b.Version >= clparams.CapellaVersion {
for _, change := range b.ExecutionChanges {
size += change.EncodingSizeSSZ()
}
}
return
}

Expand Down Expand Up @@ -285,6 +310,11 @@ func (b *BeaconBody) DecodeSSZ(buf []byte, version clparams.StateVersion) error
if version >= clparams.BellatrixVersion {
offsetExecution = ssz_utils.DecodeOffset(buf[380:])
}
// Execution to BLS changes
var blsChangesOffset uint32
if version >= clparams.CapellaVersion {
blsChangesOffset = ssz_utils.DecodeOffset(buf[384:])
}
// Decode Proposer slashings
proposerSlashingLength := 416
b.ProposerSlashings, err = ssz_utils.DecodeStaticList[*ProposerSlashing](buf, offSetProposerSlashings, offsetAttesterSlashings, uint32(proposerSlashingLength), MaxProposerSlashings)
Expand All @@ -309,19 +339,37 @@ func (b *BeaconBody) DecodeSSZ(buf []byte, version clparams.StateVersion) error
}
// Decode exits
exitLength := 112
endExitBuffer := len(buf)
endOffset := len(buf)
if b.Version >= clparams.BellatrixVersion {
endExitBuffer = int(offsetExecution)
endOffset = int(offsetExecution)
}
b.VoluntaryExits, err = ssz_utils.DecodeStaticList[*SignedVoluntaryExit](buf, offsetExits, uint32(endExitBuffer), uint32(exitLength), MaxVoluntaryExits)
b.VoluntaryExits, err = ssz_utils.DecodeStaticList[*SignedVoluntaryExit](buf, offsetExits, uint32(endOffset), uint32(exitLength), MaxVoluntaryExits)
if err != nil {
return err
}

endOffset = len(buf)
if b.Version >= clparams.CapellaVersion {
endOffset = int(blsChangesOffset)
}
if b.Version >= clparams.BellatrixVersion {
b.ExecutionPayload = new(Eth1Block)
if err := b.ExecutionPayload.DecodeSSZ(buf[offsetExecution:], b.Version); err != nil {
if offsetExecution > uint32(endOffset) || len(buf) < endOffset {
return ssz_utils.ErrBadOffset
}
fmt.Println(len(buf[offsetExecution:endOffset]))
if err := b.ExecutionPayload.DecodeSSZ(buf[offsetExecution:endOffset], b.Version); err != nil {
return err
}
}

if b.Version >= clparams.CapellaVersion {
fmt.Println(blsChangesOffset)
fmt.Println(uint32(len(buf)))
if b.ExecutionChanges, err = ssz_utils.DecodeStaticList[*SignedBLSToExecutionChange](buf, blsChangesOffset, uint32(len(buf)), 172, MaxExecutionChanges); err != nil {
return err
}

}
return nil
}
Expand Down
40 changes: 29 additions & 11 deletions cl/cltypes/beacon_block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func getTestEth1Block() *cltypes.Eth1Block {
Body: &types.RawBody{},
}
emptyBlock.Header.TxHashSSZ, _ = merkle_tree.TransactionsListRoot([][]byte{})
emptyBlock.Header.WithdrawalsHash = new(common.Hash)
return emptyBlock
}

Expand Down Expand Up @@ -94,13 +95,38 @@ var testBeaconBlockVariation = &cltypes.SignedBeaconBlock{
Deposits: []*cltypes.Deposit{createDepositTest(), createDepositTest()},
SyncAggregate: &cltypes.SyncAggregate{},
ExecutionPayload: getTestEth1Block(),
ExecutionChanges: []*cltypes.SignedBLSToExecutionChange{
{
Message: &cltypes.BLSToExecutionChange{
ValidatorIndex: 34,
To: common.HexToAddress("aaa"),
},
},
},
},
},
}

var bellatrixHash = common.HexToHash("9a5bc717ecaf6a8d6e879478003729b9ce4e71f5c4e9b4bd4dd166780894ee93")
var altairHash = common.HexToHash("36aa8fe956265d171b7ad740077ea9579e25ed3b2f7b2010016513e4ac4754cb")
var phase0Hash = common.HexToHash("83dd9e30bf61720822be889abf73760a26fb42dc9fb27fa872f845d68af92bc4")
var (
// Hashes
capellaHash = common.HexToHash("9a5bc717ecaf6a8d6e879478003729b9ce4e71f5c4e9b4bd4dd166780894ee93")
bellatrixHash = common.HexToHash("9a5bc717ecaf6a8d6e879478003729b9ce4e71f5c4e9b4bd4dd166780894ee93")
altairHash = common.HexToHash("36aa8fe956265d171b7ad740077ea9579e25ed3b2f7b2010016513e4ac4754cb")
phase0Hash = common.HexToHash("83dd9e30bf61720822be889abf73760a26fb42dc9fb27fa872f845d68af92bc4")
)

func TestCapellaBlock(t *testing.T) {
testBeaconBlockVariation.Block.Body.Version = clparams.CapellaVersion
require.Equal(t, testBeaconBlockVariation.Version(), clparams.CapellaVersion)
// Simple unit test: unmarshal + marshal + hashtreeroot
hash, err := testBeaconBlockVariation.HashSSZ()
require.NoError(t, err)
require.Equal(t, common.Hash(hash), capellaHash)
encoded, err := testBeaconBlockVariation.EncodeSSZ(nil)
require.NoError(t, err)
block2 := &cltypes.SignedBeaconBlock{}
require.NoError(t, block2.DecodeSSZWithVersion(encoded, int(clparams.CapellaVersion)))
}

func TestBellatrixBlock(t *testing.T) {
testBeaconBlockVariation.Block.Body.Version = clparams.BellatrixVersion
Expand All @@ -113,14 +139,6 @@ func TestBellatrixBlock(t *testing.T) {
require.NoError(t, err)
block2 := &cltypes.SignedBeaconBlock{}
require.NoError(t, block2.DecodeSSZWithVersion(encoded, int(clparams.BellatrixVersion)))
hash2, err := block2.HashSSZ()
require.NoError(t, err)
require.Equal(t, common.Hash(hash2), bellatrixHash)
// encode/decode for storage
storageEncoded, err := block2.EncodeForStorage()
require.NoError(t, err)
_, _, _, _, err = cltypes.DecodeBeaconBlockForStorage(storageEncoded)
require.NoError(t, err)
}

func TestAltairBlock(t *testing.T) {
Expand Down
3 changes: 2 additions & 1 deletion cl/cltypes/bls_to_execution_change.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (*BLSToExecutionChange) EncodingSizeSSZ() int {
}

type SignedBLSToExecutionChange struct {
Message BLSToExecutionChange
Message *BLSToExecutionChange
Signature [96]byte
}

Expand All @@ -66,6 +66,7 @@ func (s *SignedBLSToExecutionChange) DecodeSSZ(buf []byte) error {
if len(buf) < s.EncodingSizeSSZ() {
return ssz_utils.ErrLowBufferSize
}
s.Message = new(BLSToExecutionChange)
if err := s.Message.DecodeSSZ(buf); err != nil {
return err
}
Expand Down
29 changes: 18 additions & 11 deletions cl/cltypes/eth1_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import (
type Eth1Block struct {
Header *types.Header
// Transactions can be kept in bytes.
Body *types.RawBody
Body *types.RawBody
version clparams.StateVersion
}

func (b *Eth1Block) NumberU64() uint64 {
Expand All @@ -27,7 +28,7 @@ func (b *Eth1Block) Withdrawals() types.Withdrawals {
return types.Withdrawals(b.Body.Withdrawals)
}

func (b *Eth1Block) EncodingSizeSSZ() (size int) {
func (b *Eth1Block) EncodingSizeSSZ(version clparams.StateVersion) (size int) {
size = 508

if b.Header == nil {
Expand All @@ -41,28 +42,28 @@ func (b *Eth1Block) EncodingSizeSSZ() (size int) {
size += len(tx)
}

if b.Header.WithdrawalsHash != nil {
size += len(b.Body.Withdrawals) * 44
if version >= clparams.CapellaVersion {
size += len(b.Body.Withdrawals)*44 + 4
}

return
}

func (b *Eth1Block) DecodeSSZ(buf []byte, version clparams.StateVersion) error {
if len(buf) < b.EncodingSizeSSZ() {
if len(buf) < b.EncodingSizeSSZ(clparams.BellatrixVersion) {
return ssz_utils.ErrLowBufferSize
}
b.Header = new(types.Header)

pos := b.Header.DecodeHeaderMetadataForSSZ(buf)
// Compute block SSZ offsets.
extraDataOffset := ssz_utils.BaseExtraDataSSZOffsetBlock
transactionsOffset := ssz_utils.DecodeOffset(buf[pos : pos+4])
transactionsOffset := ssz_utils.DecodeOffset(buf[pos:])
pos += 4
var withdrawalOffset *uint32
if version >= clparams.CapellaVersion {
withdrawalOffset = new(uint32)
*withdrawalOffset = ssz_utils.DecodeOffset(buf[pos : pos+4])
*withdrawalOffset = ssz_utils.DecodeOffset(buf[pos:])
}
// Compute extra data.
b.Header.Extra = common.CopyBytes(buf[extraDataOffset:transactionsOffset])
Expand All @@ -72,8 +73,14 @@ func (b *Eth1Block) DecodeSSZ(buf []byte, version clparams.StateVersion) error {
// Compute transactions
var transactionsBuffer []byte
if withdrawalOffset == nil {
if len(transactionsBuffer) > len(buf) {
return ssz_utils.ErrLowBufferSize
}
transactionsBuffer = buf[transactionsOffset:]
} else {
if len(transactionsBuffer) > int(*withdrawalOffset) || int(*withdrawalOffset) > len(buf) {
return ssz_utils.ErrBadOffset
}
transactionsBuffer = buf[transactionsOffset:*withdrawalOffset]
}

Expand Down Expand Up @@ -145,12 +152,12 @@ func (b *Eth1Block) DecodeSSZ(buf []byte, version clparams.StateVersion) error {
return nil
}

func (b *Eth1Block) EncodeSSZ(dst []byte) ([]byte, error) {
func (b *Eth1Block) EncodeSSZ(dst []byte, version clparams.StateVersion) ([]byte, error) {
buf := dst
var err error
currentOffset := ssz_utils.BaseExtraDataSSZOffsetBlock

if b.Header.WithdrawalsHash != nil {
if version >= clparams.CapellaVersion {
currentOffset += 4
}
buf, err = b.Header.EncodeHeaderMetadataForSSZ(buf, currentOffset)
Expand All @@ -167,7 +174,7 @@ func (b *Eth1Block) EncodeSSZ(dst []byte) ([]byte, error) {
currentOffset += len(tx) + 4
}
// Write withdrawals offset if exist
if b.Header.WithdrawalsHash != nil {
if version >= clparams.CapellaVersion {
buf = append(buf, ssz_utils.OffsetSSZ(uint32(currentOffset))...)
}
// Sanity check for extra data then write it.
Expand All @@ -186,7 +193,7 @@ func (b *Eth1Block) EncodeSSZ(dst []byte) ([]byte, error) {
buf = append(buf, tx...)
}

if b.Header.WithdrawalsHash != nil {
if version >= clparams.CapellaVersion {
// Append all withdrawals SSZ
for _, withdrawal := range body.Withdrawals {
buf = append(buf, withdrawal.EncodeSSZ()...)
Expand Down
2 changes: 1 addition & 1 deletion cl/fork/id.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func getLastForkEpoch(
) uint64 {
currentEpoch := utils.GetCurrentEpoch(genesisConfig.GenesisTime, beaconConfig.SecondsPerSlot, beaconConfig.SlotsPerEpoch)
// Retrieve current fork version.
currentForkEpoch := beaconConfig.GenesisEpoch
var currentForkEpoch uint64
for _, fork := range forkList(beaconConfig.ForkVersionSchedule) {
if currentEpoch >= fork.epoch {
currentForkEpoch = fork.epoch
Expand Down
4 changes: 2 additions & 2 deletions cmd/erigon-cl/stages/stage_history_reconstruction.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ func SpawnStageHistoryReconstruction(cfg StageHistoryReconstructionCfg, s *stage
if foundLatestEth1ValidHash {
return slot <= destinationSlot, nil
}
encodedPayload := make([]byte, 0, payload.EncodingSizeSSZ())
encodedPayload, err = payload.EncodeSSZ(encodedPayload)
encodedPayload := make([]byte, 0, payload.EncodingSizeSSZ(blk.Version()))
encodedPayload, err = payload.EncodeSSZ(encodedPayload, blk.Version())
if err != nil {
return false, err
}
Expand Down
Loading

0 comments on commit 20a4ae4

Please sign in to comment.