Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flatten EIP-7002 withdrawal requests encoding #12138

Merged
merged 9 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated in consensus/misc/eip7002.go


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
Loading