Skip to content

Commit

Permalink
Flatten EIP-7002 withdrawal requests encoding (#12138)
Browse files Browse the repository at this point in the history
In summary, does away with a lot of earlier complexities related to
parsing and encoding withdrawal requests. These are now just byte
strings, essentially

Refer to the following
- ethereum/EIPs#8855 (flat requests format
update for EIP-7002)
-
https://github.com/ethereum/EIPs/pull/8934/files#diff-70472fac1debb567783ce13873323261713f3ce488a26a5c3769a9193f4a7e27R596
(Address update)

Needs interface update -
erigontech/interfaces#234

(Tasks board - #12106)
  • Loading branch information
somnathb1 authored Oct 11, 2024
1 parent e26fc8d commit 8959ee8
Show file tree
Hide file tree
Showing 10 changed files with 169 additions and 331 deletions.
83 changes: 5 additions & 78 deletions consensus/misc/eip7002.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@
package misc

import (
"encoding/binary"

"github.com/erigontech/erigon-lib/common"
"github.com/erigontech/erigon-lib/log/v3"
"github.com/erigontech/erigon/consensus"
"github.com/erigontech/erigon/core/types"
Expand All @@ -30,93 +27,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 @@ -28,6 +28,7 @@ import (
"github.com/holiman/uint256"

libcommon "github.com/erigontech/erigon-lib/common"
"github.com/erigontech/erigon-lib/common/hexutility"
types2 "github.com/erigontech/erigon-lib/types"
"github.com/erigontech/erigon/rlp"
)
Expand Down Expand Up @@ -88,9 +89,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 @@ -413,9 +412,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 @@ -616,57 +613,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 @@ -31,6 +31,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 @@ -22,24 +22,16 @@ import (
"errors"
"io"

libcommon "github.com/erigontech/erigon-lib/common"
"github.com/erigontech/erigon-lib/common/hexutil"
"github.com/erigontech/erigon-lib/common/hexutility"
rlp2 "github.com/erigontech/erigon-lib/rlp"
"github.com/erigontech/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 @@ -48,53 +40,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 @@ -105,18 +86,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 @@ -4,7 +4,7 @@ go 1.22.0

require (
github.com/erigontech/erigon-snapshot v1.3.1-0.20240814160410-2ce37904b978
github.com/erigontech/interfaces v0.0.0-20240912071218-97d86b41623a
github.com/erigontech/interfaces v0.0.0-20240930141537-21d2f6889ec4
github.com/erigontech/mdbx-go v0.38.4
github.com/erigontech/secp256k1 v1.1.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 @@ -148,8 +148,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/erigontech/erigon-snapshot v1.3.1-0.20240814160410-2ce37904b978 h1:7ECOf7Us3+/706WGZXIX84qQc6zmxQby8fGbFLiqFlU=
github.com/erigontech/erigon-snapshot v1.3.1-0.20240814160410-2ce37904b978/go.mod h1:ooHlCl+eEYzebiPu+FP6Q6SpPUeMADn8Jxabv3IKb9M=
github.com/erigontech/interfaces v0.0.0-20240912071218-97d86b41623a h1:8SkMr0APaj4LiviMVfXHRqNgWmsl8mVnNb/ioMzRedE=
github.com/erigontech/interfaces v0.0.0-20240912071218-97d86b41623a/go.mod h1:N7OUkhkcagp9+7yb4ycHsG2VWCOmuJ1ONBecJshxtLE=
github.com/erigontech/interfaces v0.0.0-20240930141537-21d2f6889ec4 h1:MFWfaE+BwmFXfNfwwuyeNImS16HIsDGB0q3u7nCpIhY=
github.com/erigontech/interfaces v0.0.0-20240930141537-21d2f6889ec4/go.mod h1:N7OUkhkcagp9+7yb4ycHsG2VWCOmuJ1ONBecJshxtLE=
github.com/erigontech/mdbx-go v0.38.4 h1:S9T7mTe9KPcFe4dOoOtVdI6gPzht9y7wMnYfUBgrQLo=
github.com/erigontech/mdbx-go v0.38.4/go.mod h1:IcOLQDPw3VM/asP6T5JVPPN4FHHgJtY16XfYjzWKVNI=
github.com/erigontech/secp256k1 v1.1.0 h1:mO3YJMUSoASE15Ya//SoHiisptUhdXExuMUN1M0X9qY=
Expand Down
Loading

0 comments on commit 8959ee8

Please sign in to comment.