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

Finish SENDFINDCONTENT implementation #440

Merged
merged 40 commits into from
Aug 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
1a6d78f
Add content handling to network scaffolding
acolytec3 Aug 1, 2023
f87f8f6
Add tests for storing and retrieving beacon content
acolytec3 Aug 2, 2023
70acd3e
Merge branch 'master' into content-handling
acolytec3 Aug 7, 2023
57516d1
Merge remote-tracking branch 'origin/master' into content-handling
acolytec3 Aug 14, 2023
d58bacc
Integration test scaffolding
acolytec3 Aug 14, 2023
93d9ebc
Add UTP handling in sendFindContent
acolytec3 Aug 14, 2023
3dce6d6
WIP
acolytec3 Aug 15, 2023
2590d4d
WIP
acolytec3 Aug 15, 2023
1750839
Finish test for finding content
acolytec3 Aug 15, 2023
1b18aaf
Turn off logging
acolytec3 Aug 15, 2023
ef7d0fc
Fix method names
acolytec3 Aug 15, 2023
6493bae
Add TODO
acolytec3 Aug 15, 2023
4c58612
Naive changes
acolytec3 Aug 15, 2023
bea7457
Merge remote-tracking branch 'origin/master' into vitest-migration
acolytec3 Aug 15, 2023
a44fb70
Fix npm scripts
acolytec3 Aug 15, 2023
8c7017e
fix leftover tape bits
acolytec3 Aug 15, 2023
d862c06
Add history network to provider setup
acolytec3 Aug 15, 2023
b3d6cff
put tests in util.spec suite
ScottyPoi Aug 15, 2023
3180a4b
fix async
ScottyPoi Aug 15, 2023
f1bc0c3
vitestify wire/types.spec.ts
ScottyPoi Aug 15, 2023
f641983
vitestify history/util.spec
ScottyPoi Aug 15, 2023
c8dad25
clear linting errors
ScottyPoi Aug 15, 2023
365fc4e
put tests into suites in beacon.spec
ScottyPoi Aug 15, 2023
b974965
resolve suite/test error in historyProtocol.spec
ScottyPoi Aug 15, 2023
9768328
resolve vitest error in receiptManager.spec
ScottyPoi Aug 15, 2023
0b606d2
vitestify socket.spec
ScottyPoi Aug 16, 2023
93c37b4
put tests in suite in protocol.spec
ScottyPoi Aug 16, 2023
cb6e1c0
put tests in suite - history/types.spec
ScottyPoi Aug 16, 2023
3703dc9
Fix integration tests
acolytec3 Aug 16, 2023
46cdaff
Fix various imports
acolytec3 Aug 17, 2023
8335e2d
lint fixes
acolytec3 Aug 17, 2023
a1691f9
Fix parens
acolytec3 Aug 17, 2023
8b03bac
Fix import paths
acolytec3 Aug 17, 2023
3471b39
Add more content handling
acolytec3 Aug 17, 2023
8659d61
Merge remote-tracking branch 'origin/master' into beacon-protocol-con…
acolytec3 Aug 21, 2023
eb37768
update package-lock
acolytec3 Aug 21, 2023
0b3b5ea
Add initial RPC stuff for Beacon network
acolytec3 Aug 21, 2023
71adac0
extend gossip test timeout
acolytec3 Aug 22, 2023
923d051
Fix timeout again
acolytec3 Aug 22, 2023
eedbc71
Remove unnecessary timeout hack
acolytec3 Aug 22, 2023
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
1,268 changes: 1,017 additions & 251 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 2 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@
"scripts": {
"preinstall": "npm run checkNpmVersion",
"checkNpmVersion": "bash ./scripts/check-npm-version.sh",
"postinstall": "npm run tapeHotFix && npm run build --workspaces --if-present",
"postinstall": "npm run build --workspaces --if-present",
"start-proxy": "npm run start -w=proxy -- --nat=localhost",
"start-browser-client": "npm run start-testnet -w=browser-client",
"start-cli": "npm run dev -w=cli",
"lint": "npm run lint -w=cli -w=portalnetwork -w=proxy",
"lint:fix": "npm run lint:fix -w=cli -w=portalnetwork -w=proxy",
"clean": "bash ./scripts/clean-root.sh",
"tapeHotFix": "sed -i -e 's/js/ts/g' node_modules/tape/bin/import-or-require.js",
"ethjsHotFix": "sed -i '/from \\S\\+\\.json'\\''/ s/;//;/from \\S\\+\\.json/ s/.*/& assert {type: \"json\"};/' node_modules/@ethereumjs/**/dist/esm/**/*.js"
"clean": "bash ./scripts/clean-root.sh"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.51.0",
Expand Down
4 changes: 3 additions & 1 deletion packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,11 @@ const main = async () => {
//@ts-ignore Because level doesn't know how to get along with itself
db,
metrics,
supportedProtocols: [ProtocolId.HistoryNetwork],
supportedProtocols: [ProtocolId.HistoryNetwork, ProtocolId.BeaconLightClientNetwork],
dataDir: args.datadir,
})
portal.discv5.enableLogs()

portal.enableLog('*ultralight*, *Portal*, *ultralight:RPC*')
let metricsServer: http.Server | undefined

Expand All @@ -132,6 +133,7 @@ const main = async () => {
}
await portal.start()

// TODO - make this more intelligent
const protocol = portal.protocols.get(ProtocolId.HistoryNetwork)
if (args.bootnode) {
protocol!.addBootNode(args.bootnode)
Expand Down
40 changes: 40 additions & 0 deletions packages/cli/src/rpc/modules/portal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import {
ContentMessageType,
AcceptMessage,
decodeHistoryNetworkContentKey,
BeaconLightClientNetwork,
BeaconLightClientNetworkContentType,
} from 'portalnetwork'
import { GetEnrResult } from '../schema/types.js'
import { isValidId } from '../util.js'
Expand Down Expand Up @@ -47,6 +49,8 @@ const methods = [
'portal_historyStore',
'portal_historyLocalContent',
'portal_historyGossip',
'portal_beaconSendFindContent',
'portal_beaconStore',

// not included in portal-network-specs
'portal_historyAddEnrs',
Expand All @@ -57,11 +61,15 @@ const methods = [
export class portal {
private _client: PortalNetwork
private _history: HistoryProtocol
private _beacon: BeaconLightClientNetwork
private logger: Debugger

constructor(client: PortalNetwork, logger: Debugger) {
this._client = client
this._history = this._client.protocols.get(ProtocolId.HistoryNetwork) as HistoryProtocol
this._beacon = this._client.protocols.get(
ProtocolId.BeaconLightClientNetwork,
) as BeaconLightClientNetwork
this.logger = logger
this.methods = middleware(this.methods.bind(this), 0, [])
this.historyNodeInfo = middleware(this.historyNodeInfo.bind(this), 0, [])
Expand Down Expand Up @@ -132,6 +140,15 @@ export class portal {
[validators.contentKey],
[validators.hex],
])
this.beaconSendFindContent = middleware(this.beaconSendFindContent.bind(this), 2, [
[validators.dstId],
[validators.hex],
])

this.beaconStore = middleware(this.beaconStore.bind(this), 2, [
[validators.hex],
[validators.hex],
])
}
async methods() {
return methods
Expand Down Expand Up @@ -512,4 +529,27 @@ export class portal {
return false
}
}

async beaconSendFindContent(params: [string, string]) {
const [nodeId, contentKey] = params
console.log(nodeId)
const res = await this._beacon.sendFindContent(nodeId, fromHexString(contentKey))
console.log(res)
const enr = this._beacon.routingTable.getWithPending(nodeId)?.value
return res && enr && '0x' + enr.seq.toString(16)
}

async beaconStore(params: [string, string]) {
const [contentKey, content] = params.map((param) => fromHexString(param))
try {
await this._beacon.store(
contentKey[0] as BeaconLightClientNetworkContentType,
toHexString(contentKey.slice(1)),
content,
)
return true
} catch {
return false
}
}
}
3 changes: 2 additions & 1 deletion packages/portalnetwork/.eslintignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/types/*
/types/*
vitest.config.unit.ts
12 changes: 5 additions & 7 deletions packages/portalnetwork/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@
"dev": "tsc --watch",
"build": "tsc",
"docs": "typedoc src/index.ts",
"tape": "NODE_OPTIONS='--loader ts-node/esm --experimental-json-modules' tape",
"test": "npm run tape -- 'test/!(integration)/**/*.spec.ts'",
"test:all": "npm run tape -- 'test/**/*.spec.ts'",
"test:integration": "npm run tape -- 'test/integration/**/*.spec.ts'",
"test": "npx vitest run test/* -c=./vitest.config.unit.ts",
"test:integration": "npx vitest run ./test/integration/*.spec.ts",
"coverage": "c8 npm run test",
"coverage:all": "c8 npm run test:all",
"lint": "../../config/cli/lint.sh",
Expand Down Expand Up @@ -60,17 +58,17 @@
"@ethereumjs/tx": "5.0.0",
"@ethereumjs/util": "9.0.0",
"@types/debug": "^4.1.7",
"@types/tape": "^4.13.2",
"@types/ws": "^7.4.7",
"@vitest/ui": "^0.34.1",
"c8": "^7.12.0",
"eslint": "^8.6.0",
"prettier": "^2.5.1",
"tape": "^5.5.3",
"testdouble": "^3.16.3",
"ts-node": "^10.4.0",
"tslib": "^2.3.1",
"typedoc": "^0.24.0",
"typedoc-plugin-markdown": "^3.11.3",
"typescript": "^4.4.2"
"typescript": "^4.4.2",
"vitest": "^0.34.1"
}
}
4 changes: 2 additions & 2 deletions packages/portalnetwork/src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { ITalkReqMessage, ITalkRespMessage } from '@chainsafe/discv5/message'
import { EventEmitter } from 'events'
import debug, { Debugger } from 'debug'
import { fromHexString, toHexString } from '@chainsafe/ssz'
import { BeaconLightClientNetwork, ProtocolId, StateProtocol } from '../subprotocols/index.js'
import { BeaconLightClientNetwork, StateProtocol } from '../subprotocols/index.js'
import {
PortalNetworkEventEmitter,
PortalNetworkMetrics,
Expand All @@ -21,7 +21,7 @@ import type { PeerId, Secp256k1PeerId } from '@libp2p/interface-peer-id'
import { createSecp256k1PeerId } from '@libp2p/peer-id-factory'
import { INodeAddress } from '@chainsafe/discv5/lib/session/nodeInfo.js'
import { PortalNetworkUTP } from '../wire/utp/PortalNetworkUtp/index.js'

import { ProtocolId } from '../types.js'
import { BaseProtocol } from '../subprotocols/protocol.js'
import { HistoryProtocol } from '../subprotocols/history/history.js'
import { Multiaddr, multiaddr } from '@multiformats/multiaddr'
Expand Down
2 changes: 1 addition & 1 deletion packages/portalnetwork/src/client/dbManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { AbstractBatchOperation, AbstractLevel } from 'abstract-level'
import { Debugger } from 'debug'
import { MemoryLevel } from 'memory-level'
import { fromHexString, serializedContentKeyToContentId } from '../index.js'
import { ProtocolId } from '../subprotocols/index.js'
import { ProtocolId } from '../index.js'

export class DBManager {
nodeId: string
Expand Down
3 changes: 2 additions & 1 deletion packages/portalnetwork/src/client/provider.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ethers } from 'ethers'
import { addRLPSerializedBlock, HistoryProtocol, ProtocolId } from '../subprotocols/index.js'
import { addRLPSerializedBlock, HistoryProtocol } from '../subprotocols/index.js'
import { ProtocolId } from '../types.js'
import { toHexString } from '../util/discv5.js'
import {
ethJsBlockToEthersBlock,
Expand Down
1 change: 1 addition & 0 deletions packages/portalnetwork/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './util/index.js'
export * from './transports/index.js'
export * from './subprotocols/index.js'
export * from './client/index.js'
export * from './types.js'
163 changes: 85 additions & 78 deletions packages/portalnetwork/src/subprotocols/beacon/beacon.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Debugger } from 'debug'
import { BaseProtocol } from '../protocol.js'
import { FoundContent, ProtocolId } from '../types.js'
import { FoundContent } from '../types.js'
import { ProtocolId } from '../../types.js'
import { PortalNetwork } from '../../client/client.js'
import debug from 'debug'
import { Union } from '@chainsafe/ssz/lib/interface.js'
Expand All @@ -18,11 +19,9 @@ import {
MessageCodes,
PortalWireMessageType,
} from '../../wire/types.js'
import { ssz } from '@lodestar/types'
import { getBeaconContentKey } from './util.js'
import { bytesToInt } from '@ethereumjs/util'
import { RequestCode } from '../../wire/index.js'

import { ssz } from '@lodestar/types'
export class BeaconLightClientNetwork extends BaseProtocol {
protocolId: ProtocolId.BeaconLightClientNetwork
beaconConfig: BeaconConfig
Expand Down Expand Up @@ -97,83 +96,88 @@ export class BeaconLightClientNetwork extends BaseProtocol {
})
break
}
} /*
const contentHash = toHexString(key)
const forkhash = decoded.value.slice(0, 4) as Uint8Array
const forkname = this.beaconConfig.forkDigest2ForkName(forkhash) as any
switch (decoded.selector) {
case BeaconLightClientNetworkContentType.LightClientOptimisticUpdate:
try {
// TODO: Figure out how to use Forks type to limit selector in ssz[forkname] below and make typescript happy
;(ssz as any)[forkname].LightClientOptimisticUpdate.deserialize(
(decoded.value as Uint8Array).slice(4),
)
} catch (err) {
this.logger(`received invalid content from ${shortId(dstId)}`)
break
}
this.logger(
`received ${
BeaconLightClientNetworkContentType[decoded.selector]
} content corresponding to ${contentHash}`,
)
await this.store(decoded.selector, contentHash, decoded.value as Uint8Array)
break
case BeaconLightClientNetworkContentType.LightClientFinalityUpdate:
try {
;(ssz as any)[forkname].LightClientFinalityUpdate.deserialize(
(decoded.value as Uint8Array).slice(4),
)
} catch (err) {
this.logger(`received invalid content from ${shortId(dstId)}`)
break
}
this.logger(
`received ${
BeaconLightClientNetworkContentType[decoded.selector]
} content corresponding to ${contentHash}`,
)
await this.store(decoded.selector, contentHash, decoded.value as Uint8Array)
break
case BeaconLightClientNetworkContentType.LightClientBootstrap:
try {
;(ssz as any)[forkname].LightClientBootstrap.deserialize(
(decoded.value as Uint8Array).slice(4),
)
} catch (err) {
this.logger(`received invalid content from ${shortId(dstId)}`)
break
}
this.logger(
`received ${
BeaconLightClientNetworkContentType[decoded.selector]
} content corresponding to ${contentHash}`,
)
await this.store(decoded.selector, contentHash, decoded.value as Uint8Array)
break
case BeaconLightClientNetworkContentType.LightClientUpdatesByRange:
try {
LightClientUpdatesByRange.deserialize((decoded.value as Uint8Array).slice(4))
} catch (err) {
this.logger(`received invalid content from ${shortId(dstId)}`)
break
case FoundContent.CONTENT: {
const contentKey = toHexString(key)
const forkhash = decoded.value.slice(0, 4) as Uint8Array
const forkname = this.beaconConfig.forkDigest2ForkName(forkhash) as any
switch (key[0]) {
case BeaconLightClientNetworkContentType.LightClientOptimisticUpdate:
try {
// TODO: Figure out how to use Forks type to limit selector in ssz[forkname] below and make typescript happy
;(ssz as any)[forkname].LightClientOptimisticUpdate.deserialize(
(decoded.value as Uint8Array).slice(4),
)
} catch (err) {
this.logger(`received invalid content from ${shortId(dstId)}`)
break
}
this.logger(
`received ${
BeaconLightClientNetworkContentType[decoded.selector]
} content corresponding to ${contentKey}`,
)
await this.store(key[0], contentKey, decoded.value as Uint8Array)
break
case BeaconLightClientNetworkContentType.LightClientFinalityUpdate:
try {
;(ssz as any)[forkname].LightClientFinalityUpdate.deserialize(
(decoded.value as Uint8Array).slice(4),
)
} catch (err) {
this.logger(`received invalid content from ${shortId(dstId)}`)
break
}
this.logger(
`received ${
BeaconLightClientNetworkContentType[decoded.selector]
} content corresponding to ${contentKey}`,
)
await this.store(key[0], contentKey, decoded.value as Uint8Array)
break
case BeaconLightClientNetworkContentType.LightClientBootstrap:
try {
;(ssz as any)[forkname].LightClientBootstrap.deserialize(
(decoded.value as Uint8Array).slice(4),
)
} catch (err) {
this.logger(`received invalid content from ${shortId(dstId)}`)
break
}
this.logger(
`received ${
BeaconLightClientNetworkContentType[decoded.selector]
} content corresponding to ${contentKey}`,
)
await this.store(key[0], contentKey, decoded.value as Uint8Array)
break
case BeaconLightClientNetworkContentType.LightClientUpdatesByRange:
try {
LightClientUpdatesByRange.deserialize((decoded.value as Uint8Array).slice(4))
} catch (err) {
this.logger(`received invalid content from ${shortId(dstId)}`)
break
}
this.logger(
`received ${
BeaconLightClientNetworkContentType[decoded.selector]
} content corresponding to ${contentKey}`,
)
await this.store(key[0], contentKey, decoded.value as Uint8Array)
break

default:
this.logger(
`received ${
BeaconLightClientNetworkContentType[decoded.selector]
} content corresponding to ${contentKey}`,
)
break
}
this.logger(
`received ${
BeaconLightClientNetworkContentType[decoded.selector]
} content corresponding to ${contentHash}`,
)
await this.store(decoded.selector, contentHash, decoded.value as Uint8Array)
break
default:
this.logger(
`received ${
BeaconLightClientNetworkContentType[decoded.selector]
} content corresponding to ${contentHash}`,
)
}*/
}
}
return decoded
}
// TODO Should we do anything other than ignore responses to FINDCONTENT messages that isn't a CONTENT response?
} catch (err: any) {
this.logger(`Error sending FINDCONTENT to ${shortId(dstId)} - ${err.message}`)
}
Expand All @@ -188,6 +192,9 @@ export class BeaconLightClientNetwork extends BaseProtocol {
if (contentType === BeaconLightClientNetworkContentType.LightClientUpdatesByRange) {
throw new Error('special handling for update ranges not supported yet')
}
this.logger(
`storing ${BeaconLightClientNetworkContentType[contentType]} content corresponding to ${contentKey}`,
)
await this.put(this.protocolId, contentKey, toHexString(value))
}
}
Loading