Skip to content

Commit

Permalink
common,util,tx: implement aip 6493 stable container txs
Browse files Browse the repository at this point in the history
debug and fix the legacy ssz encoding decoding

add a spec test for legacy ssz encoding decoding

add the ssztx boilerplate to other tx types

implement sszRaw value for 2930 tx

add 2930 spec test and debug/fix ssz encoding/decoding

add the ssz encoding decoding to 1559 tx

add eip 1559 testcase and get it working

add 4844 ssz encoding decoding

add eip 4844 testcase and get it working

define block transactions ssz type and test ssz transactionsRoot

handle ssz roots for transactions and withdrawals in block when 6493 activated

handle the roots gen in the build block

fix the transaction stable container

update the execution payload serialization deserialization for 6493

add 6493 hardfork for the testing/devnet

refactor the transaction factory ssz tx deserialization

add ssz profile<>stablecontaiber conversion spec test

add eip6493 support to common

debug and fix the block transaction withdrawal root comparision by removing null keccak hash hardcoding

enhance eip6493 tx test by testing transaction factory deserialization which uses stable container

add client eip6493 end to end spec and fix the payload generation

refactor tx serialization deserializion with respect to execution/beacon payload

add, debug and fix the transactionv1 or hex transactions validator and debug/fix the newpayloadeip6493 spec test

add 6493 to electra for kurtosis testing

console log error for debugging

console log error for debugging

txpool fix attempt

add more descriptive checks for nulloroptional

add more descriptive checks for nulloroptional

log full error

debug and fix handling of replay vs legacy tx w.r.t. v/ypartity and confirm via spec test

build fix

dev and add transaction inclusion proof to the getTransactionX apis

workaround to get the proof since stable container impl for proof seems buggy and breaking

refactor the proof format based on feedback

debug, discuss and fix the signature packing scheme

add hack to schedule 6493 on prague in cli for stablecontainer devnets

debug and fix newpayload eip6493 spec

debug rebase and spec fixes in tx utils

debug and fix block build

fix the vm build

debug and get 6493 end to end client spec working

rebase 4844 fixes

add ssz blockheader type and update the blockhash to use when ssz activated

debug and update client spec with ssz blockhash

update ssz field to receiptstrie

updates after discussion with etan

update test
  • Loading branch information
g11tech committed Oct 4, 2024
1 parent 3136bd2 commit 5baf071
Show file tree
Hide file tree
Showing 46 changed files with 1,875 additions and 79 deletions.
30 changes: 30 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/block/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"tsc": "../../config/cli/ts-compile.sh"
},
"dependencies": {
"@chainsafe/ssz": "https://github.com/ChainSafe/ssz/raw/cayman/stable-container/packages/ssz/package.tgz",
"@ethereumjs/common": "^4.4.0",
"@ethereumjs/rlp": "^5.0.2",
"@ethereumjs/trie": "^6.2.1",
Expand Down
43 changes: 19 additions & 24 deletions packages/block/src/block/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { keccak256 } from 'ethereum-cryptography/keccak.js'
// TODO: See if there is an easier way to achieve the same result.
// See: https://github.com/microsoft/TypeScript/issues/47558
// (situation will eventually improve on Typescript and/or Eslint update)
import { genTransactionsSszRoot, genWithdrawalsSszRoot } from '../helpers.js'
import {
genRequestsTrieRoot,
genTransactionsTrieRoot,
Expand Down Expand Up @@ -226,10 +227,9 @@ export class Block {
* Generates transaction trie for validation.
*/
async genTxTrie(): Promise<Uint8Array> {
return genTransactionsTrieRoot(
this.transactions,
new MerklePatriciaTrie({ common: this.common }),
)
return this.common.isActivatedEIP(6493)
? genTransactionsSszRoot(this.transactions)
: genTransactionsTrieRoot(this.transactions, new MerklePatriciaTrie({ common: this.common }))
}

/**
Expand All @@ -238,16 +238,10 @@ export class Block {
* @returns True if the transaction trie is valid, false otherwise
*/
async transactionsTrieIsValid(): Promise<boolean> {
let result
if (this.transactions.length === 0) {
result = equalsBytes(this.header.transactionsTrie, KECCAK256_RLP)
return result
}

if (this.cache.txTrieRoot === undefined) {
this.cache.txTrieRoot = await this.genTxTrie()
}
result = equalsBytes(this.cache.txTrieRoot, this.header.transactionsTrie)
const result = equalsBytes(this.cache.txTrieRoot, this.header.transactionsTrie)
return result
}

Expand Down Expand Up @@ -367,7 +361,9 @@ export class Block {
}

if (!(await this.transactionsTrieIsValid())) {
const msg = this._errorMsg('invalid transaction trie')
const msg = this._errorMsg(
`invalid transaction trie expected=${bytesToHex(this.cache.txTrieRoot!)}`,
)
throw new Error(msg)
}

Expand Down Expand Up @@ -456,6 +452,12 @@ export class Block {
return equalsBytes(this.keccakFunction(raw), this.header.uncleHash)
}

async genWithdrawalsTrie(): Promise<Uint8Array> {
return this.common.isActivatedEIP(6493)
? genWithdrawalsSszRoot(this.withdrawals!)
: genWithdrawalsTrieRoot(this.withdrawals!, new MerklePatriciaTrie({ common: this.common }))
}

/**
* Validates the withdrawal root
* @returns true if the withdrawals trie root is valid, false otherwise
Expand All @@ -465,19 +467,10 @@ export class Block {
throw new Error('EIP 4895 is not activated')
}

let result
if (this.withdrawals!.length === 0) {
result = equalsBytes(this.header.withdrawalsRoot!, KECCAK256_RLP)
return result
}

if (this.cache.withdrawalsTrieRoot === undefined) {
this.cache.withdrawalsTrieRoot = await genWithdrawalsTrieRoot(
this.withdrawals!,
new MerklePatriciaTrie({ common: this.common }),
)
this.cache.withdrawalsTrieRoot = await this.genWithdrawalsTrie()
}
result = equalsBytes(this.cache.withdrawalsTrieRoot, this.header.withdrawalsRoot!)
const result = equalsBytes(this.cache.withdrawalsTrieRoot, this.header.withdrawalsRoot!)
return result
}

Expand Down Expand Up @@ -546,7 +539,9 @@ export class Block {
toExecutionPayload(): ExecutionPayload {
const blockJSON = this.toJSON()
const header = blockJSON.header!
const transactions = this.transactions.map((tx) => bytesToHex(tx.serialize())) ?? []
const transactions = this.common.isActivatedEIP(6493)
? this.transactions.map((tx) => tx.toExecutionPayloadTx())
: this.transactions.map((tx) => bytesToHex(tx.serialize()))
const withdrawalsArr = blockJSON.withdrawals ? { withdrawals: blockJSON.withdrawals } : {}

const executionPayload: ExecutionPayload = {
Expand Down
46 changes: 34 additions & 12 deletions packages/block/src/block/constructors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
type TxOptions,
createTx,
createTxFromBlockBodyData,
createTxFromExecutionPayloadTx,
createTxFromRLP,
normalizeTxParams,
} from '@ethereumjs/tx'
Expand All @@ -25,7 +26,13 @@ import {
} from '@ethereumjs/util'

import { generateCliqueBlockExtraData } from '../consensus/clique.js'
import { genRequestsTrieRoot, genTransactionsTrieRoot, genWithdrawalsTrieRoot } from '../helpers.js'
import {
genRequestsTrieRoot,
genTransactionsSszRoot,
genTransactionsTrieRoot,
genWithdrawalsSszRoot,
genWithdrawalsTrieRoot,
} from '../helpers.js'
import {
Block,
createBlockHeader,
Expand All @@ -46,6 +53,7 @@ import type {
RequestsBytes,
WithdrawalsBytes,
} from '../types.js'
import type { Common } from '@ethereumjs/common'
import type { TypedTransaction } from '@ethereumjs/tx'
import type {
CLRequest,
Expand Down Expand Up @@ -373,7 +381,7 @@ export const createBlockFromJSONRPCProvider = async (
*/
export async function createBlockFromExecutionPayload(
payload: ExecutionPayload,
opts?: BlockOptions,
opts: BlockOptions & { common: Common },
): Promise<Block> {
const {
blockNumber: number,
Expand All @@ -389,25 +397,39 @@ export async function createBlockFromExecutionPayload(
} = payload

const txs = []
for (const [index, serializedTx] of transactions.entries()) {
for (const [index, serializedTxOrPayload] of transactions.entries()) {
try {
const tx = createTxFromRLP(hexToBytes(serializedTx as PrefixedHexString), {
common: opts?.common,
})
let tx
if (opts.common.isActivatedEIP(6493)) {
if (typeof serializedTxOrPayload === 'string') {
throw Error('EIP 6493 activated for transaction bytes')
}
tx = createTxFromExecutionPayloadTx(serializedTxOrPayload, {
common: opts?.common,
})
} else {
if (typeof serializedTxOrPayload !== 'string') {
throw Error('EIP 6493 not activated for transaction payload')
}
tx = createTxFromRLP(hexToBytes(serializedTxOrPayload as PrefixedHexString), {
common: opts?.common,
})
}
txs.push(tx)
} catch (error) {
const validationError = `Invalid tx at index ${index}: ${error}`
throw validationError
}
}

const transactionsTrie = await genTransactionsTrieRoot(
txs,
new MerklePatriciaTrie({ common: opts?.common }),
)
const transactionsTrie = opts.common.isActivatedEIP(6493)
? await genTransactionsSszRoot(txs)
: await genTransactionsTrieRoot(txs, new MerklePatriciaTrie({ common: opts?.common }))
const withdrawals = withdrawalsData?.map((wData) => createWithdrawal(wData))
const withdrawalsRoot = withdrawals
? await genWithdrawalsTrieRoot(withdrawals, new MerklePatriciaTrie({ common: opts?.common }))
? opts.common.isActivatedEIP(6493)
? genWithdrawalsSszRoot(withdrawals)
: await genWithdrawalsTrieRoot(withdrawals, new MerklePatriciaTrie({ common: opts?.common }))
: undefined

const hasDepositRequests = depositRequests !== undefined && depositRequests !== null
Expand Down Expand Up @@ -481,7 +503,7 @@ export async function createBlockFromExecutionPayload(
*/
export async function createBlockFromBeaconPayloadJSON(
payload: BeaconPayloadJSON,
opts?: BlockOptions,
opts: BlockOptions & { common: Common },
): Promise<Block> {
const executionPayload = executionPayloadFromBeaconPayload(payload)
return createBlockFromExecutionPayload(executionPayload, opts)
Expand Down
77 changes: 73 additions & 4 deletions packages/block/src/from-beacon-payload.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { bigIntToHex } from '@ethereumjs/util'

import type { ExecutionPayload } from './types.js'
import type { NumericString, PrefixedHexString, VerkleExecutionWitness } from '@ethereumjs/util'
import type {
NumericString,
PrefixedHexString,
VerkleExecutionWitness,
ssz,
} from '@ethereumjs/util'

type BeaconWithdrawal = {
index: PrefixedHexString
Expand Down Expand Up @@ -30,7 +35,41 @@ type BeaconConsolidationRequest = {
target_pubkey: PrefixedHexString
}

// Payload JSON that one gets using the beacon apis
export type BeaconFeesPerGasV1 = {
regular: PrefixedHexString | null // Quantity 64 bytes
blob: PrefixedHexString | null // Quantity 64 bytes
}

export type BeaconAccessTupleV1 = {
address: PrefixedHexString // DATA 20 bytes
storage_keys: PrefixedHexString[] // Data 32 bytes MAX_ACCESS_LIST_STORAGE_KEYS array
}

export type BeaconTransactionPayloadV1 = {
type: PrefixedHexString | null // Quantity, 1 byte
chain_id: PrefixedHexString | null // Quantity 8 bytes
nonce: PrefixedHexString | null // Quantity 8 bytes
max_fees_per_gas: BeaconFeesPerGasV1 | null
gas: PrefixedHexString | null // Quantity 8 bytes
to: PrefixedHexString | null // DATA 20 bytes
value: PrefixedHexString | null // Quantity 64 bytes
input: PrefixedHexString | null // max MAX_CALLDATA_SIZE bytes,
access_list: BeaconAccessTupleV1[] | null
max_priority_fees_per_gas: BeaconFeesPerGasV1 | null
blob_versioned_hashes: PrefixedHexString[] | null // DATA 32 bytes array
}

export type BeaconTransactionSignatureV1 = {
from: PrefixedHexString | null // DATA 20 bytes
ecdsa_signature: PrefixedHexString | null // DATA 65 bytes or null
}

type BeaconTransactionV1 = {
payload: BeaconTransactionPayloadV1
signature: BeaconTransactionSignatureV1
}

// Payload json that one gets using the beacon apis
// curl localhost:5052/eth/v2/beacon/blocks/56610 | jq .data.message.body.execution_payload
export type BeaconPayloadJSON = {
parent_hash: PrefixedHexString
Expand All @@ -46,7 +85,7 @@ export type BeaconPayloadJSON = {
extra_data: PrefixedHexString
base_fee_per_gas: NumericString
block_hash: PrefixedHexString
transactions: PrefixedHexString[]
transactions: PrefixedHexString[] | BeaconTransactionV1[]
withdrawals?: BeaconWithdrawal[]
blob_gas_used?: NumericString
excess_blob_gas?: NumericString
Expand Down Expand Up @@ -121,6 +160,36 @@ function parseExecutionWitnessFromSnakeJSON({
* The JSON data can be retrieved from a consensus layer (CL) client on this Beacon API `/eth/v2/beacon/blocks/[block number]`
*/
export function executionPayloadFromBeaconPayload(payload: BeaconPayloadJSON): ExecutionPayload {
const transactions =
typeof payload.transactions[0] === 'object'
? (payload.transactions as BeaconTransactionV1[]).map((btxv1) => {
return {
payload: {
type: btxv1.payload.type,
chainId: btxv1.payload.chain_id,
nonce: btxv1.payload.nonce,
maxFeesPerGas: btxv1.payload.max_fees_per_gas,
to: btxv1.payload.to,
value: btxv1.payload.value,
input: btxv1.payload.input,
accessList:
btxv1.payload.access_list?.map((bal: BeaconAccessTupleV1) => {
return {
address: bal.address,
storageKeys: bal.storage_keys,
}
}) ?? null,
maxPriorityFeesPerGas: btxv1.payload.max_priority_fees_per_gas,
blobVersionedHashes: btxv1.payload.blob_versioned_hashes,
},
signature: {
from: btxv1.signature.from,
ecdsaSignature: btxv1.signature.ecdsa_signature,
},
} as ssz.TransactionV1
})
: (payload.transactions as PrefixedHexString[])

const executionPayload: ExecutionPayload = {
parentHash: payload.parent_hash,
feeRecipient: payload.fee_recipient,
Expand All @@ -135,7 +204,7 @@ export function executionPayloadFromBeaconPayload(payload: BeaconPayloadJSON): E
extraData: payload.extra_data,
baseFeePerGas: bigIntToHex(BigInt(payload.base_fee_per_gas)),
blockHash: payload.block_hash,
transactions: payload.transactions,
transactions,
}

if (payload.withdrawals !== undefined && payload.withdrawals !== null) {
Expand Down
Loading

0 comments on commit 5baf071

Please sign in to comment.