Skip to content

tx: add peerdas blob transactions support #3976

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

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
4e54fac
tx: add peerdas blob transactions support
g11tech Apr 14, 2025
e62c171
add eip 7594 network wrapper for blob tx
g11tech Apr 17, 2025
79ea6be
add eip 7594 checks and engine api changes
g11tech Apr 17, 2025
8018113
add 7594 to osaka hf and fix the network wrapper validation
g11tech Apr 18, 2025
90456df
improve networkwrapper vals
g11tech Apr 18, 2025
6a4ee60
update proof validation for cell proofs network version
g11tech Apr 18, 2025
d207313
temp use ckzg
g11tech Apr 18, 2025
9ceb384
fixes
g11tech Apr 18, 2025
878db6e
load trusted setup on ckzg
g11tech Apr 18, 2025
01e71c3
load trusted setup on ckzg
g11tech Apr 18, 2025
30b5246
load trusted setup on ckzg
g11tech Apr 18, 2025
da32066
move prague genesis to testdata and add/generate osaka genesis and up…
g11tech Apr 25, 2025
6ed99ca
add blobs to cell and proofs util
g11tech Apr 25, 2025
1934d71
build and add getpayloadv5 end to end client spec, test/fix the issues
g11tech Apr 25, 2025
8e40c69
ci build
g11tech Apr 25, 2025
50c2b4f
ci build
g11tech Apr 25, 2025
bf35a5a
fix ci
g11tech Apr 25, 2025
d9a4ddd
add 7594 network wrapper tx tests and fix isssues
g11tech Apr 26, 2025
3bdcd50
fix ckzg import
g11tech May 4, 2025
3ac1a29
debug requests
g11tech May 5, 2025
949b555
add further debugging log
g11tech May 5, 2025
58300d5
ckzg for testing revert later
g11tech May 5, 2025
b033e7d
fix rebae
g11tech May 5, 2025
e886c2c
add blobs bundle debug log
g11tech May 5, 2025
621d70d
more debug log
g11tech May 8, 2025
71fd34d
remove old format transactions
g11tech May 8, 2025
361e997
reject old format tx acceptance
g11tech May 8, 2025
b112d81
add debug log
g11tech May 8, 2025
18e0ad6
exclude selection of 7594 txs if hardfork not yet happened
g11tech May 12, 2025
804156d
exclude selection of 7594 txs if hardfork not yet happened
g11tech May 12, 2025
c534b6f
remove additional console logs
g11tech May 12, 2025
f91bea7
fix breaking client tests
g11tech May 13, 2025
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
3 changes: 2 additions & 1 deletion config/cspell-ts.json
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,7 @@
"blobschedule",
"hoodi",
"peerdas",
"getpayload"
"getpayload",
"ckzg"
]
}
21 changes: 21 additions & 0 deletions package-lock.json

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

68 changes: 64 additions & 4 deletions packages/client/bin/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
randomBytes,
setLengthLeft,
} from '@ethereumjs/util'
import { trustedSetup } from '@paulmillr/trusted-setups/fast.js'
// import { trustedSetup } from '@paulmillr/trusted-setups/fast.js'
import {
keccak256 as keccak256WASM,
secp256k1Expand,
Expand All @@ -40,7 +40,7 @@ import {
import { keccak256 } from 'ethereum-cryptography/keccak.js'
import { secp256k1 } from 'ethereum-cryptography/secp256k1.js'
import { sha256 } from 'ethereum-cryptography/sha256.js'
import { KZG as microEthKZG } from 'micro-eth-signer/kzg'
// import { KZG as microEthKZG } from 'micro-eth-signer/kzg'
import * as verkle from 'micro-eth-signer/verkle'
import * as promClient from 'prom-client'
import * as yargs from 'yargs'
Expand All @@ -54,6 +54,7 @@ import { setupMetrics } from '../src/util/metrics.ts'

import type { CustomCrypto, GenesisState, GethGenesis } from '@ethereumjs/common'
import type { Address, PrefixedHexString } from '@ethereumjs/util'
import { default as ckzg } from 'c-kzg'
import type { Logger } from '../src/logging.ts'
import type { ClientOpts } from '../src/types.ts'

Expand Down Expand Up @@ -630,7 +631,66 @@ function generateAccount(): Account {
export async function getCryptoFunctions(useJsCrypto: boolean): Promise<CustomCrypto> {
const cryptoFunctions: CustomCrypto = {}

const kzg = new microEthKZG(trustedSetup)
// const kzg = new microEthKZG(trustedSetup)
ckzg.loadTrustedSetup(0)
const cKzg = {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

temp using ckzg will microsigner impls the cell fns

blobToKzgCommitment: (blob: string) => {
const blobBytes = hexToBytes(blob as PrefixedHexString)
const commitmentBytes = ckzg.blobToKzgCommitment(blobBytes)
return bytesToHex(commitmentBytes) as string
},
computeBlobProof: (blob: string, commitment: string) => {
const blobBytes = hexToBytes(blob as PrefixedHexString)
const commitmentBytes = hexToBytes(commitment as PrefixedHexString)
const proofBytes = ckzg.computeBlobKzgProof(blobBytes, commitmentBytes)
return bytesToHex(proofBytes) as string
},
verifyProof: (commitment: string, z: string, y: string, proof: string) => {
const commitmentBytes = hexToBytes(commitment as PrefixedHexString)
const zBytes = hexToBytes(z as PrefixedHexString)
const yBytes = hexToBytes(y as PrefixedHexString)
const proofBytes = hexToBytes(proof as PrefixedHexString)
return ckzg.verifyKzgProof(commitmentBytes, zBytes, yBytes, proofBytes)
},
verifyBlobProofBatch: (blobs: string[], commitments: string[], proofs: string[]) => {
const blobsBytes = blobs.map((blb) => hexToBytes(blb as PrefixedHexString))
const commitmentsBytes = commitments.map((cmt) => hexToBytes(cmt as PrefixedHexString))
const proofsBytes = proofs.map((prf) => hexToBytes(prf as PrefixedHexString))
return ckzg.verifyBlobKzgProofBatch(blobsBytes, commitmentsBytes, proofsBytes)
},
computeCells: (blob: string) => {
const blobBytes = hexToBytes(blob as PrefixedHexString)
const cellsBytes = ckzg.computeCells(blobBytes)
return cellsBytes.map((cellBytes) => bytesToHex(cellBytes)) as string[]
},
computeCellsAndProofs: (blob: string) => {
const blobBytes = hexToBytes(blob as PrefixedHexString)
const [cellsBytes, proofsBytes] = ckzg.computeCellsAndKzgProofs(blobBytes)
return [
cellsBytes.map((cellBytes) => bytesToHex(cellBytes)),
proofsBytes.map((prfBytes) => bytesToHex(prfBytes)),
] as [string[], string[]]
},
recoverCellsAndProofs: (indices: number[], cells: string[]) => {
const cellsBytes = cells.map((cell) => hexToBytes(cell as PrefixedHexString))
const [allCellsBytes, allProofsBytes] = ckzg.recoverCellsAndKzgProofs(indices, cellsBytes)
return [
allCellsBytes.map((cellBytes) => bytesToHex(cellBytes)),
allProofsBytes.map((prfBytes) => bytesToHex(prfBytes)),
] as [string[], string[]]
},
verifyCellKzgProofBatch: (
commitments: string[],
indices: number[],
cells: string[],
proofs: string[],
) => {
const commitmentsBytes = commitments.map((commit) => hexToBytes(commit as PrefixedHexString))
const cellsBytes = cells.map((cell) => hexToBytes(cell as PrefixedHexString))
const proofsBytes = proofs.map((prf) => hexToBytes(prf as PrefixedHexString))
return ckzg.verifyCellKzgProofBatch(commitmentsBytes, indices, cellsBytes, proofsBytes)
},
}
// Initialize WASM crypto if JS crypto is not specified
if (useJsCrypto === false) {
await waitReadyPolkadotSha256()
Expand Down Expand Up @@ -674,7 +734,7 @@ export async function getCryptoFunctions(useJsCrypto: boolean): Promise<CustomCr
return address
}
}
cryptoFunctions.kzg = kzg
cryptoFunctions.kzg = cKzg
cryptoFunctions.verkle = verkle
return cryptoFunctions
}
Expand Down
1 change: 1 addition & 0 deletions packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"@scure/base": "^1.2.4",
"abstract-level": "^3.0.1",
"body-parser": "^1.20.3",
"c-kzg": "^4.1.0",
"chalk": "^5.4.1",
"connect": "^3.7.0",
"cors": "^2.8.5",
Expand Down
49 changes: 46 additions & 3 deletions packages/client/src/rpc/modules/engine/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { middleware, validators } from '../../validation.ts'
import { CLConnectionManager, middleware as cmMiddleware } from './CLConnectionManager.ts'
import {
type BlobAndProofV1,
type BlobAndProofV2,
type Bytes8,
type Bytes32,
type ChainCache,
Expand Down Expand Up @@ -290,6 +291,13 @@ export class Engine {
() => this.connectionManager.updateStatus(),
)

this.getPayloadV5 = cmMiddleware(
middleware(callWithStackTrace(this.getPayloadV5.bind(this), this._rpcDebug), 1, [
[validators.bytes8],
]),
() => this.connectionManager.updateStatus(),
)

/**
* exchangeCapabilities
*/
Expand Down Expand Up @@ -325,6 +333,12 @@ export class Engine {
]),
() => this.connectionManager.updateStatus(),
)
this.getBlobsV2 = cmMiddleware(
middleware(callWithStackTrace(this.getBlobsV2.bind(this), this._rpcDebug), 1, [
[validators.array(validators.bytes32)],
]),
() => this.connectionManager.updateStatus(),
)
}

/**
Expand Down Expand Up @@ -1330,6 +1344,11 @@ export class Engine {
let checkNotAfterHf: Hardfork | null

switch (payloadVersion) {
case 5:
checkNotBeforeHf = Hardfork.Osaka
checkNotAfterHf = Hardfork.Osaka
break

case 4:
checkNotBeforeHf = Hardfork.Prague
checkNotAfterHf = Hardfork.Prague
Expand Down Expand Up @@ -1408,6 +1427,10 @@ export class Engine {
return this.getPayload(params, 4)
}

async getPayloadV5(params: [Bytes8]) {
return this.getPayload(params, 5)
}

/**
* Returns a list of engine API endpoints supported by the client
*
Expand Down Expand Up @@ -1506,11 +1529,31 @@ export class Engine {
}
}

const blobsAndProof: (BlobAndProofV1 | null)[] = []
const blobAndProofArr: (BlobAndProofV1 | null)[] = []
for (const versionedHashHex of params[0]) {
blobsAndProof.push(this.service.txPool.blobsAndProofsByHash.get(versionedHashHex) ?? null)
blobAndProofArr.push(this.service.txPool.blobAndProofByHash.get(versionedHashHex) ?? null)
}

return blobAndProofArr
}

private async getBlobsV2(params: [[Bytes32]]): Promise<BlobAndProofV2[] | null> {
if (params[0].length > 128) {
throw {
code: TOO_LARGE_REQUEST,
message: `More than 128 hashes queried`,
}
}

const blobAndProofsArr: BlobAndProofV2[] = []
for (const versionedHashHex of params[0]) {
const blobAndProofs = this.service.txPool.blobAndProofsByHash.get(versionedHashHex)
if (blobAndProofs === undefined) {
return null
}
blobAndProofsArr.push(blobAndProofs)
}

return blobsAndProof
return blobAndProofsArr
}
}
10 changes: 9 additions & 1 deletion packages/client/src/rpc/modules/engine/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ export type ForkchoiceResponseV1 = {
payloadId: Bytes8 | null
}

export type BlobsBundleV1 = {
/**
* BlobsBundle V1 & V2 are just the same object type only different is proofs are cell proofs in V2
*/
export type BlobsBundleV1OrV2 = {
commitments: Bytes48[]
blobs: Blob[]
proofs: Bytes48[]
Expand All @@ -77,6 +80,11 @@ export type BlobAndProofV1 = {
proof: PrefixedHexString
}

export type BlobAndProofV2 = {
blob: PrefixedHexString
proofs: PrefixedHexString[]
}

export type ChainCache = {
remoteBlocks: Map<string, Block>
executedBlocks: Map<string, Block>
Expand Down
4 changes: 2 additions & 2 deletions packages/client/src/rpc/modules/engine/util/getPayload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { bigIntToHex, bytesToHex } from '@ethereumjs/util'
import type { Block, ExecutionPayload } from '@ethereumjs/block'
import type { CLRequest, CLRequestType } from '@ethereumjs/util'
import type { BlobsBundle } from '../../../../miner/index.ts'
import type { BlobsBundleV1 } from '../types.ts'
import type { BlobsBundleV1OrV2 } from '../types.ts'

/**
* Formats a block to {@link ExecutionPayloadV1}.
Expand All @@ -20,7 +20,7 @@ export const blockToExecutionPayload = (
delete executionPayload.parentBeaconBlockRoot
}

const blobsBundle: BlobsBundleV1 | undefined = bundle ?? undefined
const blobsBundle: BlobsBundleV1OrV2 | undefined = bundle ?? undefined

// ethereumjs does not provide any transaction censoring detection (yet) to suggest
// overriding builder/mev-boost blocks
Expand Down
9 changes: 9 additions & 0 deletions packages/client/src/rpc/modules/eth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from '@ethereumjs/statemanager'
import {
Capability,
NetworkWrapperType,
createBlob4844TxFromSerializedNetworkWrapper,
createTx,
createTxFromRLP,
Expand Down Expand Up @@ -1160,6 +1161,14 @@ export class Eth {
if (txBuf[0] === 0x03) {
// Blob Transactions sent over RPC are expected to be in Network Wrapper format
tx = createBlob4844TxFromSerializedNetworkWrapper(txBuf, { common })
if (
common.isActivatedEIP(7594) &&
tx.networkWrapperVersion !== NetworkWrapperType.EIP7594
) {
throw Error(
`tx with networkWrapperVersion=${tx.networkWrapperVersion} sent for EIP-7594 activated hardfork=${common.hardfork()}`,
)
}

const blobGasLimit = tx.common.param('maxBlobGasPerBlock')
const blobGasPerBlob = tx.common.param('blobGasPerBlob')
Expand Down
Loading
Loading