Added separate Withdrawal data type to Caplin (#8474)

Reason: JSON formatting
This commit is contained in:
Giulio rebuffo 2023-10-14 17:59:52 +02:00 committed by GitHub
parent 9db82fee5b
commit 54ce971084
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 99 additions and 86 deletions

View File

@ -103,3 +103,7 @@ func (*KZGCommitment) Clone() clonable.Clonable {
func (*Eth1Header) Clone() clonable.Clonable {
return &Eth1Header{}
}
func (*Withdrawal) Clone() clonable.Clonable {
return &Withdrawal{}
}

View File

@ -29,11 +29,11 @@ type Eth1Block struct {
Extra *solid.ExtraData `json:"extra_data"`
BaseFeePerGas libcommon.Hash `json:"base_fee_per_gas"`
// Extra fields
BlockHash libcommon.Hash `json:"block_hash"`
Transactions *solid.TransactionsSSZ `json:"transactions"`
Withdrawals *solid.ListSSZ[*types.Withdrawal] `json:"withdrawals,omitempty"`
BlobGasUsed uint64 `json:"blob_gas_used,omitempty"`
ExcessBlobGas uint64 `json:"excess_blob_gas,omitempty"`
BlockHash libcommon.Hash `json:"block_hash"`
Transactions *solid.TransactionsSSZ `json:"transactions"`
Withdrawals *solid.ListSSZ[*Withdrawal] `json:"withdrawals,omitempty"`
BlobGasUsed uint64 `json:"blob_gas_used,omitempty"`
ExcessBlobGas uint64 `json:"excess_blob_gas,omitempty"`
// internals
version clparams.StateVersion
beaconCfg *clparams.BeaconChainConfig
@ -70,7 +70,7 @@ func NewEth1BlockFromHeaderAndBody(header *types.Header, body *types.RawBody, be
BaseFeePerGas: baseFee32,
BlockHash: header.Hash(),
Transactions: solid.NewTransactionsSSZFromTransactions(body.Transactions),
Withdrawals: solid.NewStaticListSSZFromList(body.Withdrawals, int(beaconCfg.MaxWithdrawalsPerPayload), 44),
Withdrawals: solid.NewStaticListSSZFromList(convertExecutionWithdrawalsToConsensusWithdrawals(body.Withdrawals), int(beaconCfg.MaxWithdrawalsPerPayload), 44),
beaconCfg: beaconCfg,
}
@ -145,7 +145,7 @@ func (b *Eth1Block) EncodingSizeSSZ() (size int) {
if b.version >= clparams.CapellaVersion {
if b.Withdrawals == nil {
b.Withdrawals = solid.NewStaticListSSZ[*types.Withdrawal](int(b.beaconCfg.MaxWithdrawalsPerPayload), 44)
b.Withdrawals = solid.NewStaticListSSZ[*Withdrawal](int(b.beaconCfg.MaxWithdrawalsPerPayload), 44)
}
size += b.Withdrawals.EncodingSizeSSZ() + 4
}
@ -161,7 +161,7 @@ func (b *Eth1Block) EncodingSizeSSZ() (size int) {
func (b *Eth1Block) DecodeSSZ(buf []byte, version int) error {
b.Extra = solid.NewExtraData()
b.Transactions = &solid.TransactionsSSZ{}
b.Withdrawals = solid.NewStaticListSSZ[*types.Withdrawal](int(b.beaconCfg.MaxWithdrawalsPerPayload), 44)
b.Withdrawals = solid.NewStaticListSSZ[*Withdrawal](int(b.beaconCfg.MaxWithdrawalsPerPayload), 44)
b.version = clparams.StateVersion(version)
return ssz2.UnmarshalSSZ(buf, version, b.getSchema()...)
}
@ -202,8 +202,8 @@ func (b *Eth1Block) RlpHeader() (*types.Header, error) {
withdrawalsHash = new(libcommon.Hash)
// extract all withdrawals from itearable list
withdrawals := make([]*types.Withdrawal, b.Withdrawals.Len())
b.Withdrawals.Range(func(idx int, w *types.Withdrawal, _ int) bool {
withdrawals[idx] = w
b.Withdrawals.Range(func(idx int, w *Withdrawal, _ int) bool {
withdrawals[idx] = convertConsensusWithdrawalToExecutionWithdrawal(w)
return true
})
*withdrawalsHash = types.DeriveSha(types.Withdrawals(withdrawals))
@ -251,8 +251,8 @@ func (b *Eth1Block) Version() clparams.StateVersion {
// Body returns the equivalent raw body (only eth1 body section).
func (b *Eth1Block) Body() *types.RawBody {
withdrawals := make([]*types.Withdrawal, b.Withdrawals.Len())
b.Withdrawals.Range(func(idx int, w *types.Withdrawal, _ int) bool {
withdrawals[idx] = w
b.Withdrawals.Range(func(idx int, w *Withdrawal, _ int) bool {
withdrawals[idx] = convertConsensusWithdrawalToExecutionWithdrawal(w)
return true
})
return &types.RawBody{

72
cl/cltypes/withdrawal.go Normal file
View File

@ -0,0 +1,72 @@
package cltypes
import (
"fmt"
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon-lib/common/length"
"github.com/ledgerwatch/erigon-lib/types/ssz"
"github.com/ledgerwatch/erigon/cl/merkle_tree"
"github.com/ledgerwatch/erigon/core/types"
)
type Withdrawal struct {
Index uint64 `json:"index"` // monotonically increasing identifier issued by consensus layer
Validator uint64 `json:"validatorIndex"` // index of validator associated with withdrawal
Address libcommon.Address `json:"address"` // target address for withdrawn ether
Amount uint64 `json:"amount"` // value of withdrawal in GWei
}
func (obj *Withdrawal) EncodeSSZ(buf []byte) ([]byte, error) {
buf = append(buf, ssz.Uint64SSZ(obj.Index)...)
buf = append(buf, ssz.Uint64SSZ(obj.Validator)...)
buf = append(buf, obj.Address[:]...)
buf = append(buf, ssz.Uint64SSZ(obj.Amount)...)
return buf, nil
}
func (obj *Withdrawal) DecodeSSZ(buf []byte, _ int) error {
if len(buf) < obj.EncodingSizeSSZ() {
return fmt.Errorf("[Withdrawal] err: %s", ssz.ErrLowBufferSize)
}
obj.Index = ssz.UnmarshalUint64SSZ(buf)
obj.Validator = ssz.UnmarshalUint64SSZ(buf[8:])
copy(obj.Address[:], buf[16:])
obj.Amount = ssz.UnmarshalUint64SSZ(buf[36:])
return nil
}
func (obj *Withdrawal) EncodingSizeSSZ() int {
// Validator Index (8 bytes) + Index (8 bytes) + Amount (8 bytes) + address length
return 24 + length.Addr
}
func (obj *Withdrawal) HashSSZ() ([32]byte, error) { // the [32]byte is temporary
return merkle_tree.HashTreeRoot(obj.Index, obj.Validator, obj.Address[:], obj.Amount)
}
func convertExecutionWithdrawalToConsensusWithdrawal(executionWithdrawal *types.Withdrawal) *Withdrawal {
return &Withdrawal{
Index: executionWithdrawal.Index,
Validator: executionWithdrawal.Validator,
Address: executionWithdrawal.Address,
Amount: executionWithdrawal.Amount,
}
}
func convertConsensusWithdrawalToExecutionWithdrawal(consensusWithdrawal *Withdrawal) *types.Withdrawal {
return &types.Withdrawal{
Index: consensusWithdrawal.Index,
Validator: consensusWithdrawal.Validator,
Address: consensusWithdrawal.Address,
Amount: consensusWithdrawal.Amount,
}
}
func convertExecutionWithdrawalsToConsensusWithdrawals(executionWithdrawal []*types.Withdrawal) []*Withdrawal {
ret := make([]*Withdrawal, len(executionWithdrawal))
for i, w := range executionWithdrawal {
ret[i] = convertExecutionWithdrawalToConsensusWithdrawal(w)
}
return ret
}

View File

@ -12,7 +12,6 @@ import (
"github.com/ledgerwatch/erigon/cl/cltypes/solid"
"github.com/ledgerwatch/erigon/cl/fork"
"github.com/ledgerwatch/erigon/cl/utils"
"github.com/ledgerwatch/erigon/core/types"
)
const PreAllocatedRewardsAndPenalties = 8192
@ -192,7 +191,7 @@ func ComputeTimestampAtSlot(b abstract.BeaconState, slot uint64) uint64 {
}
// ExpectedWithdrawals calculates the expected withdrawals that can be made by validators in the current epoch
func ExpectedWithdrawals(b abstract.BeaconState) []*types.Withdrawal {
func ExpectedWithdrawals(b abstract.BeaconState) []*cltypes.Withdrawal {
// Get the current epoch, the next withdrawal index, and the next withdrawal validator index
currentEpoch := Epoch(b)
nextWithdrawalIndex := b.NextWithdrawalIndex()
@ -202,7 +201,7 @@ func ExpectedWithdrawals(b abstract.BeaconState) []*types.Withdrawal {
maxValidators := uint64(b.ValidatorLength())
maxValidatorsPerWithdrawalsSweep := b.BeaconConfig().MaxValidatorsPerWithdrawalsSweep
bound := utils.Min64(maxValidators, maxValidatorsPerWithdrawalsSweep)
withdrawals := make([]*types.Withdrawal, 0, bound)
withdrawals := make([]*cltypes.Withdrawal, 0, bound)
// Loop through the validators to calculate expected withdrawals
for validatorCount := uint64(0); validatorCount < bound && len(withdrawals) != int(b.BeaconConfig().MaxWithdrawalsPerPayload); validatorCount++ {
@ -214,7 +213,7 @@ func ExpectedWithdrawals(b abstract.BeaconState) []*types.Withdrawal {
// Check if the validator is fully withdrawable
if isFullyWithdrawableValidator(b.BeaconConfig(), currentValidator, currentBalance, currentEpoch) {
// Add a new withdrawal with the validator's withdrawal credentials and balance
newWithdrawal := &types.Withdrawal{
newWithdrawal := &cltypes.Withdrawal{
Index: nextWithdrawalIndex,
Validator: nextWithdrawalValidatorIndex,
Address: libcommon.BytesToAddress(wd[12:]),
@ -224,7 +223,7 @@ func ExpectedWithdrawals(b abstract.BeaconState) []*types.Withdrawal {
nextWithdrawalIndex++
} else if isPartiallyWithdrawableValidator(b.BeaconConfig(), currentValidator, currentBalance) { // Check if the validator is partially withdrawable
// Add a new withdrawal with the validator's withdrawal credentials and balance minus the maximum effective balance
newWithdrawal := &types.Withdrawal{
newWithdrawal := &cltypes.Withdrawal{
Index: nextWithdrawalIndex,
Validator: nextWithdrawalValidatorIndex,
Address: libcommon.BytesToAddress(wd[12:]),

View File

@ -234,7 +234,7 @@ func (I *impl) ProcessVoluntaryExit(s abstract.BeaconState, signedVoluntaryExit
// ProcessWithdrawals processes withdrawals by decreasing the balance of each validator
// and updating the next withdrawal index and validator index.
func (I *impl) ProcessWithdrawals(s abstract.BeaconState, withdrawals *solid.ListSSZ[*types.Withdrawal]) error {
func (I *impl) ProcessWithdrawals(s abstract.BeaconState, withdrawals *solid.ListSSZ[*cltypes.Withdrawal]) error {
// Get the list of withdrawals, the expected withdrawals (if performing full validation),
// and the beacon configuration.
beaconConfig := s.BeaconConfig()
@ -246,8 +246,8 @@ func (I *impl) ProcessWithdrawals(s abstract.BeaconState, withdrawals *solid.Lis
if len(expectedWithdrawals) != withdrawals.Len() {
return fmt.Errorf("ProcessWithdrawals: expected %d withdrawals, but got %d", len(expectedWithdrawals), withdrawals.Len())
}
if err := solid.RangeErr[*types.Withdrawal](withdrawals, func(i int, w *types.Withdrawal, _ int) error {
if !expectedWithdrawals[i].Equal(w) {
if err := solid.RangeErr[*cltypes.Withdrawal](withdrawals, func(i int, w *cltypes.Withdrawal, _ int) error {
if *expectedWithdrawals[i] != *w {
return fmt.Errorf("ProcessWithdrawals: withdrawal %d does not match expected withdrawal", i)
}
return nil
@ -256,7 +256,7 @@ func (I *impl) ProcessWithdrawals(s abstract.BeaconState, withdrawals *solid.Lis
}
}
if err := solid.RangeErr[*types.Withdrawal](withdrawals, func(_ int, w *types.Withdrawal, _ int) error {
if err := solid.RangeErr[*cltypes.Withdrawal](withdrawals, func(_ int, w *cltypes.Withdrawal, _ int) error {
if err := state.DecreaseBalance(s, w.Validator, w.Amount); err != nil {
return err
}

View File

@ -5,7 +5,6 @@ import (
"github.com/ledgerwatch/erigon/cl/cltypes"
"github.com/ledgerwatch/erigon/cl/cltypes/solid"
"github.com/ledgerwatch/erigon/cl/transition/machine"
"github.com/ledgerwatch/erigon/core/types"
)
var _ machine.Interface = (*Impl)(nil)
@ -15,7 +14,7 @@ type Impl struct {
FnVerifyTransition func(s abstract.BeaconState, block *cltypes.BeaconBlock) error
FnProcessSlots func(s abstract.BeaconState, slot uint64) error
FnProcessBlockHeader func(s abstract.BeaconState, block *cltypes.BeaconBlock) error
FnProcessWithdrawals func(s abstract.BeaconState, withdrawals *solid.ListSSZ[*types.Withdrawal]) error
FnProcessWithdrawals func(s abstract.BeaconState, withdrawals *solid.ListSSZ[*cltypes.Withdrawal]) error
FnProcessExecutionPayload func(s abstract.BeaconState, payload *cltypes.Eth1Block) error
FnProcessRandao func(s abstract.BeaconState, randao [96]byte, proposerIndex uint64) error
FnProcessEth1Data func(state abstract.BeaconState, eth1Data *cltypes.Eth1Data) error
@ -41,7 +40,7 @@ func (i Impl) ProcessBlockHeader(s abstract.BeaconState, block *cltypes.BeaconBl
return i.FnProcessBlockHeader(s, block)
}
func (i Impl) ProcessWithdrawals(s abstract.BeaconState, withdrawals *solid.ListSSZ[*types.Withdrawal]) error {
func (i Impl) ProcessWithdrawals(s abstract.BeaconState, withdrawals *solid.ListSSZ[*cltypes.Withdrawal]) error {
return i.FnProcessWithdrawals(s, withdrawals)
}

View File

@ -5,7 +5,6 @@ import (
"github.com/ledgerwatch/erigon/cl/abstract"
"github.com/ledgerwatch/erigon/cl/cltypes"
"github.com/ledgerwatch/erigon/cl/cltypes/solid"
"github.com/ledgerwatch/erigon/core/types"
)
type Interface interface {
@ -30,7 +29,7 @@ type SlotProcessor interface {
type BlockHeaderProcessor interface {
ProcessBlockHeader(s abstract.BeaconState, block *cltypes.BeaconBlock) error
ProcessWithdrawals(s abstract.BeaconState, withdrawals *solid.ListSSZ[*types.Withdrawal]) error
ProcessWithdrawals(s abstract.BeaconState, withdrawals *solid.ListSSZ[*cltypes.Withdrawal]) error
ProcessExecutionPayload(s abstract.BeaconState, payload *cltypes.Eth1Block) error
ProcessRandao(s abstract.BeaconState, randao [96]byte, proposerIndex uint64) error
ProcessEth1Data(state abstract.BeaconState, eth1Data *cltypes.Eth1Data) error

View File

@ -22,11 +22,8 @@ import (
"io"
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon-lib/common/length"
"github.com/ledgerwatch/erigon-lib/types/clonable"
"github.com/ledgerwatch/erigon-lib/types/ssz"
"github.com/ledgerwatch/erigon/cl/merkle_tree"
"github.com/ledgerwatch/erigon/common/hexutil"
"github.com/ledgerwatch/erigon/rlp"
)
@ -42,11 +39,6 @@ type Withdrawal struct {
Amount uint64 `json:"amount"` // value of withdrawal in GWei
}
func (obj *Withdrawal) Equal(other *Withdrawal) bool {
return obj.Index == other.Index && obj.Validator == other.Validator &&
obj.Address == other.Address && obj.Amount == other.Amount
}
func (obj *Withdrawal) EncodingSize() int {
encodingSize := 21 /* Address */
encodingSize++
@ -84,34 +76,6 @@ func (obj *Withdrawal) EncodeRLP(w io.Writer) error {
return rlp.EncodeInt(obj.Amount, w, b[:])
}
func (obj *Withdrawal) EncodeSSZ(buf []byte) ([]byte, error) {
buf = append(buf, ssz.Uint64SSZ(obj.Index)...)
buf = append(buf, ssz.Uint64SSZ(obj.Validator)...)
buf = append(buf, obj.Address[:]...)
buf = append(buf, ssz.Uint64SSZ(obj.Amount)...)
return buf, nil
}
func (obj *Withdrawal) DecodeSSZ(buf []byte, _ int) error {
if len(buf) < obj.EncodingSizeSSZ() {
return fmt.Errorf("[Withdrawal] err: %s", ssz.ErrLowBufferSize)
}
obj.Index = ssz.UnmarshalUint64SSZ(buf)
obj.Validator = ssz.UnmarshalUint64SSZ(buf[8:])
copy(obj.Address[:], buf[16:])
obj.Amount = ssz.UnmarshalUint64SSZ(buf[36:])
return nil
}
func (obj *Withdrawal) EncodingSizeSSZ() int {
// Validator Index (8 bytes) + Index (8 bytes) + Amount (8 bytes) + address length
return 24 + length.Addr
}
func (obj *Withdrawal) HashSSZ() ([32]byte, error) { // the [32]byte is temporary
return merkle_tree.HashTreeRoot(obj.Index, obj.Validator, obj.Address[:], obj.Amount)
}
func (obj *Withdrawal) DecodeRLP(s *rlp.Stream) error {
_, err := s.List()
if err != nil {

View File

@ -5,9 +5,6 @@ import (
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/ledgerwatch/erigon/common"
)
func TestWithdrawalsHash(t *testing.T) {
@ -23,24 +20,3 @@ func TestWithdrawalsHash(t *testing.T) {
// Its Keccak should be returned, not the node itself.
assert.Equal(t, libcommon.HexToHash("82cc6fbe74c41496b382fcdf25216c5af7bdbb5a3929e8f2e61bd6445ab66436"), hash)
}
// Test taken from: https://github.com/ethereum/consensus-spec-tests/tree/master/tests/mainnet/capella/ssz_static/Withdrawal/ssz_random/case_1
var testWithdrawalEncodedSSZ = common.Hex2Bytes("09b99ded9629457f21c3c177a3cf80dedbbcbcbeee17b2395d5d3f839fc1ba3559d1a73ef53b8a5325e25ad2")
var testWithdrawalsSSZHash = libcommon.HexToHash("c1ec17957781f09ab3d8dbfcdfaa6c3b40a1679d3d124588f77a2da5ebb3555f")
var testWithdrawal = &Withdrawal{
Index: 9170781944418253065,
Validator: 16033042974434771745,
Address: libcommon.HexToAddress("0xdbbcbcbeee17b2395d5d3f839fc1ba3559d1a73e"),
Amount: 15157676145812061173,
}
func TestWithdrawalSSZ(t *testing.T) {
withdrawal := &Withdrawal{}
require.NoError(t, withdrawal.DecodeSSZ(testWithdrawalEncodedSSZ, 0))
require.Equal(t, withdrawal, testWithdrawal)
a, _ := withdrawal.EncodeSSZ(nil)
require.Equal(t, a, testWithdrawalEncodedSSZ)
hashSSZ, err := withdrawal.HashSSZ()
require.NoError(t, err)
require.Equal(t, libcommon.Hash(hashSSZ), testWithdrawalsSSZHash)
}