Skip to content

Commit

Permalink
Flatten EIP-7002 withdrawal requests encoding (#12456)
Browse files Browse the repository at this point in the history
Cherry pick #12138 into `release/2.61`

Co-authored-by: Somnath <[email protected]>
  • Loading branch information
yperbasis and somnathb1 authored Oct 24, 2024
1 parent 42c0d13 commit c9954b5
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 313 deletions.
84 changes: 5 additions & 79 deletions consensus/misc/eip7002.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
package misc

import (
"encoding/binary"

"github.com/ledgerwatch/log/v3"

"github.com/ledgerwatch/erigon-lib/common"

"github.com/ledgerwatch/erigon/consensus"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/params"
Expand All @@ -16,93 +12,23 @@ import (
// (May have to move it to config json later for cross-chain compatibility)
// TODO @somnathb1 Probably not needed outside of EVM
const (
ExcessWithdrawalReqsSlot = 0
WithdrawalReqCountSlot = 1
WithdrawalReqQueueHeadSlot = 2
WithdrawalReqQueueTailSlot = 3
WithdrawalReqQueueStorageOffset = 4
MaxWithdrawalReqsPerBlock = 16
TargetWithdrawalReqsPerBlock = 2
MinWithdrawalReqFee = 1
WithdrawalReqFeeUpdFraction = 17
WithdrawalRequestDataLen = 76 // addr + pubkey + amt
)

// const abiStr = `[
// {
// "inputs": [],
// "name": "read_withdrawal_requests",
// "outputs": [
// {
// "components": [
// {
// "internalType": "bytes20",
// "name": "sourceAddress",
// "type": "bytes20"
// },
// {
// "internalType": "bytes32",
// "name": "validatorPubKey1",
// "type": "bytes32"
// },
// {
// "internalType": "bytes16",
// "name": "validatorPubKey2",
// "type": "bytes16"
// },
// {
// "internalType": "uint64",
// "name": "amount",
// "type": "uint64"
// }
// ],
// "internalType": "struct WithdrawalContract.ValidatorWithdrawalRequest[]",
// "name": "",
// "type": "tuple[]"
// }
// ],
// "stateMutability": "nonpayable",
// "type": "function"
// }
// ]`

func DequeueWithdrawalRequests7002(syscall consensus.SystemCall) types.Requests {
res, err := syscall(params.WithdrawalRequestAddress, nil)
if err != nil {
log.Warn("Err with syscall to WithdrawalRequestAddress", "err", err)
return nil
}
// Parse out the exits - using the bytes array returned
// Just append the contract outputs
var reqs types.Requests
lenPerReq := 20 + 48 + 8 // addr + pubkey + amt
for i := 0; i <= len(res)-lenPerReq; i += lenPerReq {
var pubkey [48]byte
copy(pubkey[:], res[i+20:i+68])
for i := 0; i <= len(res)-WithdrawalRequestDataLen; i += WithdrawalRequestDataLen {

wr := &types.WithdrawalRequest{
SourceAddress: common.BytesToAddress(res[i : i+20]),
ValidatorPubkey: pubkey,
Amount: binary.BigEndian.Uint64(res[i+68:]),
RequestData: [WithdrawalRequestDataLen]byte(res[i : i+WithdrawalRequestDataLen]),
}
reqs = append(reqs, wr)
}
return reqs

// Alternatively unpack using the abi methods
// wAbi, _ := abi.JSON(strings.NewReader(abiStr))
// wAbi.Unpack("read_withdrawal_requests", wrs)

// type R struct {
// sourceAddress [20]byte
// validatorPubKey1 [32] byte
// validatorPubKey2 [16] byte
// amount uint64
// }
// Ret := make([]R, 0)
// wAbi.UnpackIntoInterface(Ret, "read_withdrawal_requests", wrs)

// reqs := make(types.Requests, 0)

// for r := range(Ret) {
// req := types.NewRequest(Ret)
// reqs = append(reqs, types.NewRequest())
// }
}
57 changes: 9 additions & 48 deletions core/types/encdec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/holiman/uint256"
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon-lib/common/hexutility"
types2 "github.com/ledgerwatch/erigon-lib/types"
"github.com/ledgerwatch/erigon/rlp"
)
Expand Down Expand Up @@ -71,9 +72,7 @@ func (tr *TRand) RandWithdrawal() *Withdrawal {

func (tr *TRand) RandWithdrawalRequest() *WithdrawalRequest {
return &WithdrawalRequest{
SourceAddress: [20]byte(tr.RandBytes(20)),
ValidatorPubkey: [48]byte(tr.RandBytes(48)),
Amount: *tr.RandUint64(),
RequestData: [WithdrawalRequestDataLen]byte(tr.RandBytes(WithdrawalRequestDataLen)),
}
}

Expand Down Expand Up @@ -396,9 +395,7 @@ func compareDeposits(t *testing.T, a, b *DepositRequest) {
}

func compareWithdrawalRequests(t *testing.T, a, b *WithdrawalRequest) {
check(t, "WithdrawalRequest.SourceAddress", a.SourceAddress, b.SourceAddress)
check(t, "WithdrawalRequest.ValidatorPubkey", a.ValidatorPubkey, b.ValidatorPubkey)
check(t, "WithdrawalRequest.Amount", a.Amount, b.Amount)
check(t, "WithdrawalRequest.Amount", a.RequestData, b.RequestData)
}

func compareConsolidationRequests(t *testing.T, a, b *ConsolidationRequest) {
Expand Down Expand Up @@ -599,57 +596,21 @@ func TestConsolidationReqsEncodeDecode(t *testing.T) {

func TestWithdrawalReqsEncodeDecode(t *testing.T) {
wx1 := WithdrawalRequest{
SourceAddress: libcommon.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
ValidatorPubkey: [48]byte{},
Amount: 0,
RequestData: [WithdrawalRequestDataLen]byte(hexutility.MustDecodeHex("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001fefefefefefefefe")),
}
wx1.ValidatorPubkey[47] = 0x01
wx2 := WithdrawalRequest{
SourceAddress: libcommon.HexToAddress("0x8a0a19589531694250d570040a0c4b74576919b8"),
ValidatorPubkey: [48]byte{},
Amount: 0xfffffffffffffffe,
}
wx2.ValidatorPubkey[47] = 0x02
wxs := append(Requests{}, &wx1, &wx2)

root := DeriveSha(wxs)
if root.String() != "0x143e24a803c0dc2ae5381184ad5fe9e45ac2c82c671bc3eafdc090642fc16501" {
t.Errorf("Root mismatch %s", root.String())
RequestData: [WithdrawalRequestDataLen]byte(hexutility.MustDecodeHex("0x8a0a19589531694250d570040a0c4b74576919b8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001fefefefefefefefe")),
}

var wx3, wx4 WithdrawalRequest
var buf1, buf2 bytes.Buffer
wx1.EncodeRLP(&buf1)
wx2.EncodeRLP(&buf2)

wx3.DecodeRLP(buf1.Bytes())
wx4.DecodeRLP(buf2.Bytes())
wxs = Requests{}
wxs = append(wxs, &wx3, &wx4)
root = DeriveSha(wxs)
if root.String() != "0x143e24a803c0dc2ae5381184ad5fe9e45ac2c82c671bc3eafdc090642fc16501" {
t.Errorf("Root mismatch %s", root.String())
}

/*
// Breakdown of block encoding with withdrawal requests - expected
c0c0f8a0
b84a
01
f84794
a94f5374fce5edbc8e2a8697c15331677e6ebf0b
b0
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
80
b852
01
f84f94
8a0a19589531694250d570040a0c4b74576919b8
b0
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002
88
fffffffffffffffe
*/

if wx1.RequestData != wx3.RequestData || wx2.RequestData != wx4.RequestData {
t.Errorf("error: incorrect encode/decode for WithdrawalRequest")
}
}
1 change: 1 addition & 0 deletions core/types/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
const WithdrawalRequestType byte = 0x01
const DepositRequestType byte = 0x00
const ConsolidationRequestType byte = 0x02
const WithdrawalRequestDataLen = 76 // addr + pubkey + amt

type Request interface {
EncodeRLP(io.Writer) error
Expand Down
72 changes: 23 additions & 49 deletions core/types/withdrawal_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,16 @@ import (
// "fmt"
"io"

libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon-lib/common/hexutil"
"github.com/ledgerwatch/erigon-lib/common/hexutility"
rlp2 "github.com/ledgerwatch/erigon-lib/rlp"
"github.com/ledgerwatch/erigon/rlp"
)

// EIP-7002 Withdrawal Request see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7002.md
type WithdrawalRequest struct {
SourceAddress libcommon.Address
ValidatorPubkey [BLSPubKeyLen]byte // bls
Amount uint64
RequestData [WithdrawalRequestDataLen]byte
}

type WithdrawalRequestJson struct {
SourceAddress libcommon.Address `json:"sourceAddress"`
ValidatorPubkey string `json:"validatorPubkey"`
Amount hexutil.Uint64 `json:"amount"`
RequestData string
}

func (w *WithdrawalRequest) RequestType() byte {
Expand All @@ -34,53 +26,42 @@ func (w *WithdrawalRequest) RequestType() byte {

// encodingSize implements RequestData.
func (w *WithdrawalRequest) EncodingSize() (encodingSize int) {
encodingSize += 70 // 1 + 20 + 1 + 48 (0x80 + addrSize, 0x80 + BLSPubKeyLen)
encodingSize++
encodingSize += rlp.IntLenExcludingHead(w.Amount)
encodingSize += rlp2.ListPrefixLen(encodingSize)
encodingSize += 1 // RequestType
return
return WithdrawalRequestDataLen + 1
}
func (w *WithdrawalRequest) EncodeRLP(b io.Writer) (err error) {
var buf bytes.Buffer
bb := make([]byte, 10)
if err = rlp.Encode(&buf, w.SourceAddress); err != nil {
return err
}
if err = rlp.Encode(&buf, w.ValidatorPubkey); err != nil {
if _, err = b.Write([]byte{WithdrawalRequestType}); err != nil {
return err
}
if err = rlp.EncodeInt(w.Amount, &buf, bb); err != nil {
if _, err = b.Write(w.RequestData[:]); err != nil {
return err
}
rlp2.EncodeListPrefix(buf.Len(), bb)
return
}

if _, err = b.Write([]byte{WithdrawalRequestType}); err != nil {
return err
}
if _, err = b.Write(bb[0:2]); err != nil {
return err
func (w *WithdrawalRequest) Encode() []byte {
if w == nil {
return nil
}
if _, err = b.Write(buf.Bytes()); err != nil {
return err
return append([]byte{WithdrawalRequestType}, w.RequestData[:]...)
}

func (w *WithdrawalRequest) DecodeRLP(input []byte) error {
if len(input) != WithdrawalRequestDataLen+1 {
return errors.New("Incorrect size for decoding WithdrawalRequest RLP")
}
return
w.RequestData = [76]byte(input[1:])
return nil
}

func (w *WithdrawalRequest) DecodeRLP(input []byte) error { return rlp.DecodeBytes(input[1:], w) }
func (w *WithdrawalRequest) copy() Request {
return &WithdrawalRequest{
SourceAddress: w.SourceAddress,
ValidatorPubkey: w.ValidatorPubkey,
Amount: w.Amount,
RequestData: [WithdrawalRequestDataLen]byte(bytes.Clone(w.RequestData[:])),
}
}

func (w *WithdrawalRequest) MarshalJSON() ([]byte, error) {
tt := WithdrawalRequestJson{
SourceAddress: w.SourceAddress,
ValidatorPubkey: hexutility.Encode(w.ValidatorPubkey[:]),
Amount: hexutil.Uint64(w.Amount),
RequestData: hexutility.Encode(w.RequestData[:]),
}
return json.Marshal(tt)
}
Expand All @@ -91,18 +72,11 @@ func (w *WithdrawalRequest) UnmarshalJSON(input []byte) error {
if err != nil {
return err
}

validatorKey, err := hexutil.Decode(tt.ValidatorPubkey)
if err != nil {
return err
}
if len(validatorKey) != BLSPubKeyLen {
return errors.New("WithdrawalRequest ValidatorPubkey len after UnmarshalJSON doesn't match BLSKeyLen")
if len(tt.RequestData) != WithdrawalRequestDataLen {
return errors.New("Cannot unmarshal request data, length mismatch")
}

w.ValidatorPubkey = [BLSPubKeyLen]byte(validatorKey)
w.Amount = tt.Amount.Uint64()
w.SourceAddress = tt.SourceAddress
w.RequestData = [WithdrawalRequestDataLen]byte(hexutility.MustDecodeString(tt.RequestData))
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion erigon-lib/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.22.0
require (
github.com/erigontech/mdbx-go v0.27.24
github.com/ledgerwatch/erigon-snapshot v1.3.1-0.20240805114253-42da880260bb
github.com/ledgerwatch/interfaces v0.0.0-20241002205050-75df22664246
github.com/ledgerwatch/interfaces v0.0.0-20241024115450-4e9be51e57e7
github.com/ledgerwatch/log/v3 v3.9.0
github.com/ledgerwatch/secp256k1 v1.0.0
github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417
Expand Down
4 changes: 2 additions & 2 deletions erigon-lib/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,8 @@ github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
github.com/ledgerwatch/erigon-snapshot v1.3.1-0.20240805114253-42da880260bb h1:bsoVxjnQGxhOODRmkdrbkRTB9+sIduguoNMSZPRRoTI=
github.com/ledgerwatch/erigon-snapshot v1.3.1-0.20240805114253-42da880260bb/go.mod h1:3AuPxZc85jkehh/HA9h8gabv5MSi3kb/ddtzBsTVJFo=
github.com/ledgerwatch/interfaces v0.0.0-20241002205050-75df22664246 h1:EdO/Ovw2FGIaf/RSzlhL4naHAid541WQ4q2yQ+bDHOM=
github.com/ledgerwatch/interfaces v0.0.0-20241002205050-75df22664246/go.mod h1:ugQv1QllJzBny3cKZKxUrSnykkjkBgm27eQM6dnGAcc=
github.com/ledgerwatch/interfaces v0.0.0-20241024115450-4e9be51e57e7 h1:q6nNkackUuI9xbwcDdhh0ft2QJsoIVNRZe9KR08tkxU=
github.com/ledgerwatch/interfaces v0.0.0-20241024115450-4e9be51e57e7/go.mod h1:ugQv1QllJzBny3cKZKxUrSnykkjkBgm27eQM6dnGAcc=
github.com/ledgerwatch/log/v3 v3.9.0 h1:iDwrXe0PVwBC68Dd94YSsHbMgQ3ufsgjzXtFNFVZFRk=
github.com/ledgerwatch/log/v3 v3.9.0/go.mod h1:EiAY6upmI/6LkNhOVxb4eVsmsP11HZCnZ3PlJMjYiqE=
github.com/ledgerwatch/secp256k1 v1.0.0 h1:Usvz87YoTG0uePIV8woOof5cQnLXGYa162rFf3YnwaQ=
Expand Down
Loading

0 comments on commit c9954b5

Please sign in to comment.