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

util: Change withdrawal amount representation from Wei to Gwei #2483

Merged
merged 6 commits into from
Jan 17, 2023
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
5 changes: 2 additions & 3 deletions packages/client/test/rpc/engine/withdrawals.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ for (const { name, withdrawals, withdrawalsRoot, gethBlockRlp } of testCases) {
await Block.genWithdrawalsTrieRoot(withdrawals.map(Withdrawal.fromWithdrawalData))
).toString('hex')
t.equal(withdrawalsRoot, computedWithdrawalsRoot, 'withdrawalsRoot compuation should match')
const { server, common } = await setupChain(genesisJSON, 'post-merge', { engine: true })
const { server } = await setupChain(genesisJSON, 'post-merge', { engine: true })

let req = params('engine_forkchoiceUpdatedV2', [validForkChoiceState, validPayloadAttributes])
let expectRes = checkError(
Expand Down Expand Up @@ -141,10 +141,9 @@ for (const { name, withdrawals, withdrawalsRoot, gethBlockRlp } of testCases) {

if (gethBlockRlp !== undefined) {
// check if stateroot matches
const gethBlock = Block.fromRLPSerializedBlock(Buffer.from(gethBlockRlp, 'hex'), { common })
t.equal(
payload!.stateRoot,
`0x${gethBlock.header.stateRoot.toString('hex')}`,
'0x23eadd91fca55c0e14034e4d63b2b3ed43f2e807b6bf4d276b784ac245e7fa3f',
'stateRoot should match'
)
}
Expand Down
5 changes: 5 additions & 0 deletions packages/util/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
*/
export * from './constants'

/**
* Units helpers
*/
export * from './units'

/**
* Account class and helper functions
*/
Expand Down
2 changes: 2 additions & 0 deletions packages/util/src/units.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/** Easy conversion from Gwei to wei */
export const GWEI_TO_WEI = BigInt(1000000000)
12 changes: 9 additions & 3 deletions packages/util/src/withdrawal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { TypeOutput, toType } from './types'
import type { AddressLike, BigIntLike } from './types'

/**
* Flexible input data type for EIP-4895 withdrawal data
* Flexible input data type for EIP-4895 withdrawal data with amount in Gwei to
* match CL representation and for eventual ssz withdrawalsRoot
*/
export type WithdrawalData = {
index: BigIntLike
Expand All @@ -15,13 +16,14 @@ export type WithdrawalData = {
}

/**
* JSON RPC interface for EIP-4895 withdrawal data
* JSON RPC interface for EIP-4895 withdrawal data with amount in Gwei to
* match CL representation and for eventual ssz withdrawalsRoot
*/
export interface JsonRpcWithdrawal {
index: string // QUANTITY - bigint 8 bytes
validatorIndex: string // QUANTITY - bigint 8 bytes
address: string // DATA, 20 Bytes address to withdraw to
amount: string // QUANTITY - bigint amount in wei 32 bytes
amount: string // QUANTITY - bigint amount in Gwei 8 bytes
}

export type WithdrawalBuffer = [Buffer, Buffer, Buffer, Buffer]
Expand All @@ -33,11 +35,15 @@ export class Withdrawal {
/**
* This constructor assigns and validates the values.
* Use the static factory methods to assist in creating a Withdrawal object from varying data types.
* Its amount is in Gwei to match CL representation and for eventual ssz withdrawalsRoot
*/
constructor(
public readonly index: bigint,
public readonly validatorIndex: bigint,
public readonly address: Address,
/**
* withdrawal amount in Gwei to match the CL repesentation and eventually ssz withdrawalsRoot
*/
public readonly amount: bigint
) {}

Expand Down
6 changes: 4 additions & 2 deletions packages/vm/src/buildBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Block } from '@ethereumjs/block'
import { ConsensusType } from '@ethereumjs/common'
import { RLP } from '@ethereumjs/rlp'
import { Trie } from '@ethereumjs/trie'
import { Address, TypeOutput, Withdrawal, toBuffer, toType } from '@ethereumjs/util'
import { Address, GWEI_TO_WEI, TypeOutput, Withdrawal, toBuffer, toType } from '@ethereumjs/util'

import { Bloom } from './bloom'
import { calculateMinerReward, encodeReceipt, rewardAccount } from './runBlock'
Expand Down Expand Up @@ -129,7 +129,9 @@ export class BlockBuilder {
// although this should never happen as no withdrawals with 0
// amount should ever land up here.
if (amount === 0n) continue
await rewardAccount(this.vm.eei, address, amount)
// Withdrawal amount is represented in Gwei so needs to be
// converted to wei
await rewardAccount(this.vm.eei, address, amount * GWEI_TO_WEI)
}
}

Expand Down
14 changes: 12 additions & 2 deletions packages/vm/src/runBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@ import { Block } from '@ethereumjs/block'
import { ConsensusType, Hardfork } from '@ethereumjs/common'
import { RLP } from '@ethereumjs/rlp'
import { Trie } from '@ethereumjs/trie'
import { Account, Address, bigIntToBuffer, bufArrToArr, intToBuffer, short } from '@ethereumjs/util'
import {
Account,
Address,
GWEI_TO_WEI,
bigIntToBuffer,
bufArrToArr,
intToBuffer,
short,
} from '@ethereumjs/util'
import { debug as createDebugLogger } from 'debug'

import { Bloom } from './bloom'
Expand Down Expand Up @@ -328,7 +336,9 @@ async function assignWithdrawals(this: VM, block: Block): Promise<void> {
const { address, amount } = withdrawal
// skip touching account if no amount update
if (amount === BigInt(0)) continue
await rewardAccount(state, address, amount)
// Withdrawal amount is represented in Gwei so needs to be
// converted to wei
await rewardAccount(state, address, amount * GWEI_TO_WEI)
}
}

Expand Down
8 changes: 4 additions & 4 deletions packages/vm/test/api/EIPs/eip-4895-withdrawals.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Blockchain, parseGethGenesisState } from '@ethereumjs/blockchain'
import { Chain, Common, Hardfork } from '@ethereumjs/common'
import { decode } from '@ethereumjs/rlp'
import { FeeMarketEIP1559Transaction } from '@ethereumjs/tx'
import { Address, KECCAK256_RLP, Withdrawal, zeros } from '@ethereumjs/util'
import { Address, GWEI_TO_WEI, KECCAK256_RLP, Withdrawal, zeros } from '@ethereumjs/util'
import * as tape from 'tape'

import genesisJSON = require('../../../../client/test/testdata/geth-genesis/withdrawals.json')
Expand Down Expand Up @@ -106,7 +106,7 @@ tape('EIP4895 tests', (t) => {
const address = new Address(Buffer.from(addresses[i], 'hex'))
const amount = amounts[i]
const balance = (await vm.stateManager.getAccount(address)).balance
st.equals(BigInt(amount), balance, 'balance ok')
st.equals(BigInt(amount) * GWEI_TO_WEI, balance, 'balance ok')
}

st.ok(zeros(32).equals(result!), 'withdrawals happen after transactions')
Expand Down Expand Up @@ -173,7 +173,7 @@ tape('EIP4895 tests', (t) => {
postState = (await vm.eei.getStateRoot()).toString('hex')
st.equal(
postState,
'7f7510a0cb6203f456e34ec3e2ce30d6c5590ded42c10a9cf3f24784119c5afb',
'23eadd91fca55c0e14034e4d63b2b3ed43f2e807b6bf4d276b784ac245e7fa3f',
'post state should match'
)
st.end()
Expand Down Expand Up @@ -220,7 +220,7 @@ tape('EIP4895 tests', (t) => {

st.equal(
block.header.stateRoot.toString('hex'),
'7f7510a0cb6203f456e34ec3e2ce30d6c5590ded42c10a9cf3f24784119c5afb',
'23eadd91fca55c0e14034e4d63b2b3ed43f2e807b6bf4d276b784ac245e7fa3f',
'correct state root should be generated'
)

Expand Down