diff --git a/packages/portalnetwork/src/networks/headState/headStateNetwork.ts b/packages/portalnetwork/src/networks/headState/headStateNetwork.ts new file mode 100644 index 000000000..a80a97259 --- /dev/null +++ b/packages/portalnetwork/src/networks/headState/headStateNetwork.ts @@ -0,0 +1,41 @@ +import type { ENR } from '@chainsafe/enr' +import { + BaseNetwork, + type ContentLookupResponse, + NetworkId, + type BaseNetworkConfig, +} from '../../index.js' +import debug from 'debug' +import { bytesToUnprefixedHex } from '@ethereumjs/util' +import { distance } from '@chainsafe/discv5' + +export class HeadStateNetwork extends BaseNetwork { + networkName = 'HeadStateNetwork' + networkId = NetworkId.HeadStateNetwork + + constructor({ client, db, radius, maxStorage }: BaseNetworkConfig) { + super({ client, networkId: NetworkId.HeadStateNetwork, db, radius, maxStorage }) + this.logger = debug(this.enr.nodeId.slice(0, 5)).extend('Portal').extend('HeadStateNetwork') + this.routingTable.setLogger(this.logger) + } + + public interested = (contentId: Uint8Array) => { + const bits = contentId.length + const compareId = this.enr.nodeId.slice(0, bits) + const d = distance(compareId, bytesToUnprefixedHex(contentId)) + return d <= this.nodeRadius + } + + store(contentKey: Uint8Array, value: Uint8Array): Promise { + throw new Error('Method not implemented.') + } + public findContentLocally = async (contentKey: Uint8Array): Promise => { + throw new Error('Method not implemented') + } + public sendFindContent = async ( + enr: ENR, + key: Uint8Array, + ): Promise => { + throw new Error('Method not implemented') + } +} diff --git a/packages/portalnetwork/src/networks/headState/types.ts b/packages/portalnetwork/src/networks/headState/types.ts new file mode 100644 index 000000000..6c885c6d9 --- /dev/null +++ b/packages/portalnetwork/src/networks/headState/types.ts @@ -0,0 +1,171 @@ +import { ByteVectorType, ContainerType, ListCompositeType } from '@chainsafe/ssz' +import { Bytes32Type } from '../types.js' +import { Nibbles, TrieNode, TrieProof, type AddressHash, type TNibbles, type TTrieProof } from '../state/types.js' + +// Network content type definitions +export enum HeadStateNetworkContentType { + AccountTrieDiff = 0x30, + AccountTrieNode = 0x31, + ContractTrieDiff = 0x32, + ContractTrieNode = 0x33, +} + +// Common type aliases +type BlockHash = Uint8Array +type Path = Uint8Array + +// Trie node and diff base types +export const TrieNodeListType = new ListCompositeType(TrieNode, 65536) +export const TrieDiffType = new ContainerType({ + before: TrieNodeListType, + after: TrieNodeListType, +}) + +// Account Trie types +export type AccountTrieNode = { + path: TNibbles + blockHash: BlockHash +} + +export type AccountTrieNodeValue = { + proof: TTrieProof +} + +export type AccountTrieDiff = { + path: Path + blockHash: BlockHash +} + +export type AccountTrieDiffValue = { + subtrieDiff: { + before: TTrieProof + after: TTrieProof + } +} + +// Contract Trie types +export type ContractTrieNode = { + path: TNibbles + addressHash: AddressHash + blockHash: BlockHash +} + +export type ContractTrieNodeValue = { + storageProof: TTrieProof + accountProof: TTrieProof +} + +export type ContractTrieDiff = { + path: Path + blockHash: BlockHash +} + +export type ContractTrieDiffValue = { + subtrieDiff: { + before: TTrieProof + after: TTrieProof + } + accountProof: TTrieProof +} + +// SSZ serialization types +const PathType = new ByteVectorType(1) + +export const AccountTrieNodeSszType = new ContainerType({ + path: Nibbles, + blockHash: Bytes32Type, +}) + +export const AccountTrieNodeValueSszType = new ContainerType({ + proof: TrieProof, +}) + +export const AccountTrieDiffSszType = new ContainerType({ + path: PathType, + blockHash: Bytes32Type, +}) + +export const AccountTrieDiffValueSszType = new ContainerType({ + subtrieDiff: TrieDiffType, +}) + +export const ContractTrieNodeSszType = new ContainerType({ + path: Nibbles, + addressHash: Bytes32Type, + blockHash: Bytes32Type, +}) + +export const ContractTrieNodeValueSszType = new ContainerType({ + storageProof: TrieProof, + accountProof: TrieProof, +}) + +export const ContractTrieDiffSszType = new ContainerType({ + path: PathType, + blockHash: Bytes32Type, +}) + +export const ContractTrieDiffValueSszType = new ContainerType({ + subtrieDiff: TrieDiffType, + accountProof: TrieProof, +}) + +// Content type mapping +export type HeadStateNetworkContent = + T extends HeadStateNetworkContentType.AccountTrieDiff + ? AccountTrieDiff + : T extends HeadStateNetworkContentType.AccountTrieNode + ? AccountTrieNode + : T extends HeadStateNetworkContentType.ContractTrieDiff + ? ContractTrieDiff + : T extends HeadStateNetworkContentType.ContractTrieNode + ? ContractTrieNode + : never + +export type HeadStateNetworkContentValue = + T extends HeadStateNetworkContentType.AccountTrieDiff + ? AccountTrieDiffValue + : T extends HeadStateNetworkContentType.AccountTrieNode + ? AccountTrieNodeValue + : T extends HeadStateNetworkContentType.ContractTrieDiff + ? ContractTrieDiffValue + : T extends HeadStateNetworkContentType.ContractTrieNode + ? ContractTrieNodeValue + : never + +// Serialization helpers +const contentKeySerializers: { + [T in HeadStateNetworkContentType]: { + serialize: (content: HeadStateNetworkContent) => Uint8Array + } +} = { + [HeadStateNetworkContentType.AccountTrieDiff]: AccountTrieDiffSszType, + [HeadStateNetworkContentType.AccountTrieNode]: AccountTrieNodeSszType, + [HeadStateNetworkContentType.ContractTrieDiff]: ContractTrieDiffSszType, + [HeadStateNetworkContentType.ContractTrieNode]: ContractTrieNodeSszType, +} + +const contentValueSerializers: { + [T in HeadStateNetworkContentType]: { + serialize: (content: HeadStateNetworkContentValue) => Uint8Array + } +} = { + [HeadStateNetworkContentType.AccountTrieDiff]: AccountTrieDiffValueSszType, + [HeadStateNetworkContentType.AccountTrieNode]: AccountTrieNodeValueSszType, + [HeadStateNetworkContentType.ContractTrieDiff]: ContractTrieDiffValueSszType, + [HeadStateNetworkContentType.ContractTrieNode]: ContractTrieNodeValueSszType, +} + +export function getContentKey( + type: T, + content: HeadStateNetworkContent, +) { + return Uint8Array.from([type, ...contentKeySerializers[type].serialize(content)]) +} + +export function getContentValue( + type: T, + content: HeadStateNetworkContentValue, +) { + return contentValueSerializers[type].serialize(content) +} \ No newline at end of file diff --git a/packages/portalnetwork/src/networks/types.ts b/packages/portalnetwork/src/networks/types.ts index 9bdcb371e..d9b5bc1a5 100644 --- a/packages/portalnetwork/src/networks/types.ts +++ b/packages/portalnetwork/src/networks/types.ts @@ -24,12 +24,14 @@ const BYTE_SIZE = 256 // subnetwork IDs export enum NetworkId { + HeadStateNetwork = '0x5009', StateNetwork = '0x500a', HistoryNetwork = '0x500b', BeaconChainNetwork = '0x500c', CanonicalTxIndexNetwork = '0x500d', VerkleStateNetwork = '0x500e', TransactionGossipNetwork = '0x500f', + Angelfood_HeadStateNetwork = '0x5049', Angelfood_StateNetwork = '0x504a', Angelfood_HistoryNetwork = '0x504b', Angelfood_BeaconChainNetwork = '0x504c', @@ -39,19 +41,23 @@ export enum NetworkId { UTPNetwork = '0x757470', } -export type SubNetwork = T extends '0x500a' - ? HistoryNetwork - : T extends '0x504a' - ? HistoryNetwork - : T extends '0x500b' - ? StateNetwork - : T extends '0x504b' - ? StateNetwork - : T extends '0x500c' - ? BeaconNetwork - : T extends '0x504c' - ? BeaconNetwork - : never +export type SubNetwork = T extends '0x5009' + ? HeadStateNetwork + : T extends '0x5049' + ? HeadStateNetwork + : T extends '0x500a' + ? HistoryNetwork + : T extends '0x504a' + ? HistoryNetwork + : T extends '0x500b' + ? StateNetwork + : T extends '0x504b' + ? StateNetwork + : T extends '0x500c' + ? BeaconNetwork + : T extends '0x504c' + ? BeaconNetwork + : never export class Bloom { bitvector: Uint8Array