Skip to content

Commit

Permalink
Fixes and first test
Browse files Browse the repository at this point in the history
  • Loading branch information
acolytec3 committed Feb 14, 2025
1 parent 40c4d12 commit fbfd478
Show file tree
Hide file tree
Showing 5 changed files with 946 additions and 23 deletions.
13 changes: 4 additions & 9 deletions packages/portalnetwork/src/networks/history/history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
} from './types.js'
import {
getContentKey,
getEphemeralHeaderDbKey,
verifyPostCapellaHeaderProof,
verifyPreCapellaHeaderProof,
verifyPreMergeHeaderProof,
Expand Down Expand Up @@ -394,10 +395,7 @@ export class HistoryNetwork extends BaseNetwork {
this.logger(errorMessage)
throw new Error(errorMessage)
}
const hashKey = getContentKey(
HistoryNetworkContentType.EphemeralHeader,
firstHeader.hash(),
)
const hashKey = getEphemeralHeaderDbKey(firstHeader.hash())
await this.put(hashKey, bytesToHex(payload[0]))
let prevHeader = firstHeader
// Should get maximum of 256 headers
Expand All @@ -406,12 +404,9 @@ export class HistoryNetwork extends BaseNetwork {
const ancestorHeader = BlockHeader.fromRLPSerializedHeader(header, {
setHardfork: true,
})
if (equalsBytes(prevHeader.hash(), ancestorHeader.parentHash)) {
if (equalsBytes(prevHeader.parentHash, ancestorHeader.hash())) {
// Verify that ancestor header matches parent hash of previous header
const hashKey = getContentKey(
HistoryNetworkContentType.EphemeralHeader,
ancestorHeader.hash(),
)
const hashKey = getEphemeralHeaderDbKey(ancestorHeader.hash())
await this.put(hashKey, bytesToHex(header))
prevHeader = ancestorHeader
} else {
Expand Down
17 changes: 13 additions & 4 deletions packages/portalnetwork/src/networks/history/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,22 @@ export const getContentKey = (
case HistoryNetworkContentType.BlockBody:
case HistoryNetworkContentType.Receipt: {
if (!(key instanceof Uint8Array))
throw new Error('block hash is required to generate contentId')
throw new Error('block hash is required to generate contentKey')
encodedKey = Uint8Array.from([contentType, ...key])
break
}
case HistoryNetworkContentType.BlockHeaderByNumber: {
if (typeof key !== 'bigint') throw new Error('block number is required to generate contentId')
if (typeof key !== 'bigint')
throw new Error('block number is required to generate contentKey')
encodedKey = BlockHeaderByNumberKey(key)
break
}
case HistoryNetworkContentType.EphemeralHeader: {
if (typeof key !== 'object' || !('blockHash' in key) || !('ancestorCount' in key))
throw new Error('block hash and ancestor count are required to generate contentId')
throw new Error('block hash and ancestor count are required to generate contentKey')
encodedKey = Uint8Array.from([
contentType,
EphemeralHeaderKey.serialize({
...EphemeralHeaderKey.serialize({
blockHash: key.blockHash,
ancestorCount: key.ancestorCount,
}),
Expand All @@ -93,6 +94,14 @@ export const getContentKey = (
return encodedKey
}

/**
* Generates a database key for an ephemeral header being stored in the DB
* @param blockHash hash for ephemeral header being stored
* @returns database key for ephemeral header
*/
export const getEphemeralHeaderDbKey = (blockHash: Uint8Array) => {
return Uint8Array.from([HistoryNetworkContentType.EphemeralHeader, ...blockHash])
}
/**
* Generates the contentId from a serialized History Network Content Key used to calculate the distance between a node ID and the content key
* @param contentType the type of content (block header, block body, receipt, header_by_number)
Expand Down
30 changes: 20 additions & 10 deletions packages/portalnetwork/src/util/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { Block, BlockHeader } from '@ethereumjs/block'
import { TransactionFactory } from '@ethereumjs/tx'
import { TypeOutput, bigIntToHex, bytesToHex, intToHex, setLengthLeft, toBytes, toType } from '@ethereumjs/util'
import {
TypeOutput,
bigIntToHex,
bytesToHex,
intToHex,
setLengthLeft,
toBytes,
toType,
} from '@ethereumjs/util'
import { VM } from '@ethereumjs/vm'
import debug from 'debug'
import { ethers } from 'ethers'
Expand Down Expand Up @@ -235,6 +243,7 @@ export function blockHeaderFromRpc(blockParams: JsonRpcBlock, options?: BlockOpt
mixHash,
nonce,
baseFeePerGas,
withdrawalsRoot,
} = blockParams

const blockHeader = BlockHeader.fromHeaderData(
Expand All @@ -255,6 +264,7 @@ export function blockHeaderFromRpc(blockParams: JsonRpcBlock, options?: BlockOpt
mixHash,
nonce,
baseFeePerGas,
withdrawalsRoot,
},
{ ...options, setHardfork: true },
)
Expand Down Expand Up @@ -298,15 +308,15 @@ export function formatBlockResponse(block: Block, includeTransactions: boolean)
const header = parsedBlock.header

const withdrawalsAttr =
header.withdrawalsRoot !== undefined
? {
withdrawalsRoot: header.withdrawalsRoot!,
withdrawals: parsedBlock.withdrawals,
}
: {}
header.withdrawalsRoot !== undefined
? {
withdrawalsRoot: header.withdrawalsRoot!,
withdrawals: parsedBlock.withdrawals,
}
: {}

const transactions = block.transactions.map((tx, txIndex) =>
includeTransactions ? toJSONRPCTx(tx, block, txIndex) : bytesToHex(tx.hash()),
includeTransactions ? toJSONRPCTx(tx, block, txIndex) : bytesToHex(tx.hash()),
)

return {
Expand Down Expand Up @@ -366,7 +376,7 @@ export function toJSONRPCTx(tx: TypedTransaction, block?: Block, txIndex?: numbe
r: txJSON.r!,
s: txJSON.s!,
maxFeePerBlobGas: txJSON.maxFeePerBlobGas,
blobVersionedHashes: txJSON.blobVersionedHashes
blobVersionedHashes: txJSON.blobVersionedHashes,
}
}

Expand All @@ -376,4 +386,4 @@ export function formatResponse(result: string) {
jsonrpc: '2.0',
result,
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { assert, describe, it } from 'vitest'
import { blockHeaderFromRpc } from '@ethereumjs/block/header-from-rpc'
import type { BlockHeader, JsonRpcBlock } from '@ethereumjs/block'
import latestBlocks from './testData/latest3Blocks.json'
import {
EphemeralHeaderPayload,
HistoryNetworkContentType,
PortalNetwork,
getContentKey,
getEphemeralHeaderDbKey,
} from '../../../src/index.js'
import { hexToBytes } from '@ethereumjs/util'
describe('ephemeral header handling', () => {
it('should be able to store a valid ephemeral header payload', async () => {
const node = await PortalNetwork.create({})
const network = node.network()['0x500b']
const headers: BlockHeader[] = []
headers.push(blockHeaderFromRpc(latestBlocks[0] as JsonRpcBlock, { setHardfork: true }))
headers.push(blockHeaderFromRpc(latestBlocks[1] as JsonRpcBlock, { setHardfork: true }))
headers.push(blockHeaderFromRpc(latestBlocks[2] as JsonRpcBlock, { setHardfork: true }))
const headerPayload = EphemeralHeaderPayload.serialize(headers.map((h) => h.serialize()))
const contentKey = getContentKey(HistoryNetworkContentType.EphemeralHeader, {
blockHash: headers[0].hash(),
ancestorCount: headers.length,
})
await network?.store(contentKey, headerPayload)
const storedHeaderPayload = await network?.get(getEphemeralHeaderDbKey(headers[0].hash()))
assert.deepEqual(hexToBytes(storedHeaderPayload!), headers[0].serialize())
})
})
Loading

0 comments on commit fbfd478

Please sign in to comment.