Skip to content

Commit 88fe0e5

Browse files
committed
refactor withdrawal and enhance spec test
1 parent 9d7b6d4 commit 88fe0e5

File tree

5 files changed

+79
-26
lines changed

5 files changed

+79
-26
lines changed

packages/block/src/block.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import type {
2626
TxOptions,
2727
TypedTransaction,
2828
} from '@ethereumjs/tx'
29+
import type { WithdrawalBuffer } from '@ethereumjs/util'
2930

3031
/**
3132
* An object that represents the block.
@@ -178,7 +179,7 @@ export class Block {
178179
uncleHeaders.push(BlockHeader.fromValuesArray(uncleHeaderData, uncleOpts))
179180
}
180181

181-
const withdrawals = withdrawalsBuffer
182+
const withdrawals = (withdrawalsBuffer as WithdrawalBuffer[])
182183
?.map(([index, validatorIndex, address, amount]) => ({
183184
index,
184185
validatorIndex,
@@ -500,12 +501,7 @@ export class Block {
500501
toJSON(): JsonBlock {
501502
const withdrawalsAttr = this.withdrawals
502503
? {
503-
withdrawals: this.withdrawals.map((wt) => ({
504-
index: bigIntToHex(wt.index),
505-
validatorIndex: bigIntToHex(wt.validatorIndex),
506-
address: '0x' + wt.address.buf.toString('hex'),
507-
amount: bigIntToHex(wt.amount),
508-
})),
504+
withdrawals: this.withdrawals.map((wt) => wt.toJSON()),
509505
}
510506
: {}
511507
return {

packages/block/src/types.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@ import type {
77
JsonTx,
88
TxData,
99
} from '@ethereumjs/tx'
10-
import type { AddressLike, BigIntLike, BufferLike, WithdrawalData } from '@ethereumjs/util'
10+
import type {
11+
AddressLike,
12+
BigIntLike,
13+
BufferLike,
14+
JsonRpcWithdrawal,
15+
WithdrawalBuffer,
16+
WithdrawalData,
17+
} from '@ethereumjs/util'
1118

1219
/**
1320
* An object to set to which blockchain the blocks and their headers belong. This could be specified
@@ -112,17 +119,18 @@ export interface BlockData {
112119
withdrawals?: Array<WithdrawalData>
113120
}
114121

122+
export type WithdrawalsBuffer = WithdrawalBuffer[]
123+
115124
export type BlockBuffer =
116125
| [BlockHeaderBuffer, TransactionsBuffer, UncleHeadersBuffer]
117-
| [BlockHeaderBuffer, TransactionsBuffer, UncleHeadersBuffer, WithdrawalBuffer]
126+
| [BlockHeaderBuffer, TransactionsBuffer, UncleHeadersBuffer, WithdrawalsBuffer]
118127
export type BlockHeaderBuffer = Buffer[]
119-
export type BlockBodyBuffer = [TransactionsBuffer, UncleHeadersBuffer, WithdrawalBuffer?]
128+
export type BlockBodyBuffer = [TransactionsBuffer, UncleHeadersBuffer, WithdrawalsBuffer?]
120129
/**
121130
* TransactionsBuffer can be an array of serialized txs for Typed Transactions or an array of Buffer Arrays for legacy transactions.
122131
*/
123132
export type TransactionsBuffer = Buffer[][] | Buffer[]
124133
export type UncleHeadersBuffer = Buffer[][]
125-
export type WithdrawalBuffer = Buffer[][]
126134

127135
/**
128136
* An object with the block's data represented as strings.
@@ -160,13 +168,6 @@ export interface JsonHeader {
160168
withdrawalsRoot?: string
161169
}
162170

163-
export interface JsonRpcWithdrawal {
164-
index: string // QUANTITY - bigint 8 bytes
165-
validatorIndex: string // QUANTITY - bigint 8 bytes
166-
address: string // DATA, 20 Bytes address to withdraw to
167-
amount: string // QUANTITY - bigint amount in wei 32 bytes
168-
}
169-
170171
/*
171172
* Based on https://ethereum.org/en/developers/docs/apis/json-rpc/
172173
*/

packages/block/test/eip4895block.spec.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import { Chain, Common, Hardfork } from '@ethereumjs/common'
2-
import { Address, KECCAK256_RLP } from '@ethereumjs/util'
2+
import { decode } from '@ethereumjs/rlp'
3+
import { Address, KECCAK256_RLP, Withdrawal } from '@ethereumjs/util'
34
import * as tape from 'tape'
45

56
import { Block } from '../src/block'
67
import { BlockHeader } from '../src/header'
78

8-
import type { WithdrawalData } from '@ethereumjs/util'
9+
import type { WithdrawalBuffer, WithdrawalData } from '@ethereumjs/util'
10+
11+
const gethWithdrawals8BlockRlp =
12+
'f903e1f90213a0fe950635b1bd2a416ff6283b0bbd30176e1b1125ad06fa729da9f3f4c1c61710a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794aa00000000000000000000000000000000000000a07f7510a0cb6203f456e34ec3e2ce30d6c5590ded42c10a9cf3f24784119c5afba056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080018401c9c380802f80a0ff0000000000000000000000000000000000000000000000000000000000000088000000000000000007a0b695b29ec7ee934ef6a68838b13729f2d49fffe26718de16a1a9ed94a4d7d06dc0c0f901c6da8082ffff94000000000000000000000000000000000000000080f83b0183010000940100000000000000000000000000000000000000a00100000000000000000000000000000000000000000000000000000000000000f83b0283010001940200000000000000000000000000000000000000a00200000000000000000000000000000000000000000000000000000000000000f83b0383010002940300000000000000000000000000000000000000a00300000000000000000000000000000000000000000000000000000000000000f83b0483010003940400000000000000000000000000000000000000a00400000000000000000000000000000000000000000000000000000000000000f83b0583010004940500000000000000000000000000000000000000a00500000000000000000000000000000000000000000000000000000000000000f83b0683010005940600000000000000000000000000000000000000a00600000000000000000000000000000000000000000000000000000000000000f83b0783010006940700000000000000000000000000000000000000a00700000000000000000000000000000000000000000000000000000000000000'
913

1014
const common = new Common({
1115
eips: [4895],
@@ -25,7 +29,23 @@ common.hardforkBlock = function (hardfork: string | undefined) {
2529
return BigInt(0)
2630
}
2731

28-
tape('EIP1559 tests', function (t) {
32+
tape('EIP4895 tests', function (t) {
33+
t.test('should correctly generate withdrawalsRoot', async function (st) {
34+
// get withdwalsArray
35+
const gethBlockBufferArray = decode(Buffer.from(gethWithdrawals8BlockRlp, 'hex'))
36+
const withdrawals = (gethBlockBufferArray[3] as WithdrawalBuffer[]).map((wa) =>
37+
Withdrawal.fromValuesArray(wa)
38+
)
39+
st.equal(withdrawals.length, 8, '8 withdrawals should have been found')
40+
const gethWitdrawalsRoot = (gethBlockBufferArray[0] as Buffer[])[16] as Buffer
41+
st.deepEqual(
42+
await Block.genWithdrawalsTrieRoot(withdrawals),
43+
gethWitdrawalsRoot,
44+
'withdrawalsRoot should be valid'
45+
)
46+
st.end()
47+
})
48+
2949
t.test('Header tests', function (st) {
3050
const earlyCommon = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Istanbul })
3151
st.throws(() => {

packages/util/src/withdrawal.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Address } from './address'
2+
import { bigIntToHex } from './bytes'
23
import { TypeOutput, toType } from './types'
34

45
import type { AddressLike, BigIntLike } from './types'
@@ -10,6 +11,15 @@ export type WithdrawalData = {
1011
amount: BigIntLike
1112
}
1213

14+
export interface JsonRpcWithdrawal {
15+
index: string // QUANTITY - bigint 8 bytes
16+
validatorIndex: string // QUANTITY - bigint 8 bytes
17+
address: string // DATA, 20 Bytes address to withdraw to
18+
amount: string // QUANTITY - bigint amount in wei 32 bytes
19+
}
20+
21+
export type WithdrawalBuffer = [Buffer, Buffer, Buffer, Buffer]
22+
1323
export class Withdrawal {
1424
constructor(
1525
public readonly index: bigint,
@@ -33,14 +43,20 @@ export class Withdrawal {
3343
return new Withdrawal(index, validatorIndex, address, amount)
3444
}
3545

46+
public static fromValuesArray(withdrawalArray: WithdrawalBuffer) {
47+
if (withdrawalArray.length !== 4) {
48+
throw Error(`Invalid withdrawalArray length expected=4 actual=${withdrawalArray.length}`)
49+
}
50+
const [index, validatorIndex, address, amount] = withdrawalArray
51+
return Withdrawal.fromWithdrawalData({ index, validatorIndex, address, amount })
52+
}
53+
3654
/**
3755
* Convert a withdrawal to a buffer array
3856
* @param withdrawal the withdrawal to convert
3957
* @returns buffer array of the withdrawal
4058
*/
41-
public static toBufferArray(
42-
withdrawal: Withdrawal | WithdrawalData
43-
): [Buffer, Buffer, Buffer, Buffer] {
59+
public static toBufferArray(withdrawal: Withdrawal | WithdrawalData): WithdrawalBuffer {
4460
const { index, validatorIndex, address, amount } = withdrawal
4561
const indexBuffer =
4662
toType(index, TypeOutput.BigInt) === BigInt(0)
@@ -67,4 +83,13 @@ export class Withdrawal {
6783
raw() {
6884
return Withdrawal.toBufferArray(this)
6985
}
86+
87+
toJSON() {
88+
return {
89+
index: bigIntToHex(this.index),
90+
validatorIndex: bigIntToHex(this.validatorIndex),
91+
address: '0x' + this.address.buf.toString('hex'),
92+
amount: bigIntToHex(this.amount),
93+
}
94+
}
7095
}

packages/util/test/withdrawal.spec.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import * as tape from 'tape'
33

44
import { Withdrawal, bigIntToHex, intToHex } from '../src'
55

6+
import type { WithdrawalBuffer } from '../src'
7+
68
const withdrawalsVector = [
79
{
810
Index: 0,
@@ -66,18 +68,27 @@ tape('Withdrawal', (t) => {
6668
// gethWithdrawals8Rlp is rlp encoded block with withdrawals in the 4th element of the top array
6769
const gethWithdrawalsBuffer = decode(Buffer.from(gethWithdrawals8BlockRlp, 'hex'))[3]!
6870
const gethWithdrawalsRlp = Buffer.from(encode(gethWithdrawalsBuffer)).toString('hex')
69-
t.test('Correct fromWithdrawalData and toBufferArray', (st) => {
71+
t.test('fromWithdrawalData and toBufferArray', (st) => {
7072
const withdrawals = withdrawalsGethVector.map(Withdrawal.fromWithdrawalData)
7173
const withdrawalsToBufferArr = withdrawals.map((wt) => wt.raw())
7274
const withdrawalsToRlp = Buffer.from(encode(withdrawalsToBufferArr)).toString('hex')
7375
st.equal(gethWithdrawalsRlp, withdrawalsToRlp, 'The withdrawals to buffer should match')
7476
st.end()
7577
})
7678

77-
t.test(`Direct withdrawalData to toBufferArray`, (st) => {
79+
t.test('toBufferArray from withdrawalData', (st) => {
7880
const withdrawalsDataToBufferArr = withdrawalsGethVector.map(Withdrawal.toBufferArray)
7981
const withdrawalsDataToRlp = Buffer.from(encode(withdrawalsDataToBufferArr)).toString('hex')
8082
st.equal(gethWithdrawalsRlp, withdrawalsDataToRlp, 'The withdrawals to buffer should match')
8183
st.end()
8284
})
85+
86+
t.test('fromValuesArray and toJSON', (st) => {
87+
const withdrawals = (gethWithdrawalsBuffer as WithdrawalBuffer[]).map(
88+
Withdrawal.fromValuesArray
89+
)
90+
const withdrawalsJson = withdrawals.map((wt) => wt.toJSON())
91+
st.deepEqual(withdrawalsGethVector, withdrawalsJson, 'Withdrawals json should match')
92+
st.end()
93+
})
8394
})

0 commit comments

Comments
 (0)