Fluffy portal testnet support (#2383)

* Bump portal-mainnet repo.

* Update command line arguments and parsing on startup.

* Read in angelfood bootstrap nodes and update Fluffy guide.

* Configure subnetwork protocol ids.
This commit is contained in:
web3-developer 2024-06-18 15:32:57 +08:00 committed by GitHub
parent 8926da02b6
commit e3d14bd921
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 134 additions and 73 deletions

View File

@ -56,17 +56,6 @@ type
PortalCmd* = enum PortalCmd* = enum
noCommand noCommand
PortalNetwork* = enum
none
mainnet
testnet
# The networks alias Portal sub-protocols
Network* = enum
beacon
history
state
PortalConf* = object PortalConf* = object
logLevel* {. logLevel* {.
desc: desc:
@ -94,27 +83,37 @@ type
name: "listen-address" name: "listen-address"
.}: IpAddress .}: IpAddress
portalNetwork* {. portalNetworkDeprecated* {.
hidden,
desc:
"DEPRECATED: The --portal-network flag will be removed in the future, " &
"please use the drop in replacement --network flag instead",
defaultValue: none(PortalNetwork),
name: "portal-network"
.}: Option[PortalNetwork]
network* {.
desc: desc:
"Select which Portal network to join. This will set the " & "Select which Portal network to join. This will set the " &
"Portal network specific bootstrap nodes automatically", "Portal network specific bootstrap nodes automatically",
defaultValue: PortalNetwork.mainnet, defaultValue: PortalNetwork.mainnet,
name: "portal-network" name: "network"
.}: PortalNetwork .}: PortalNetwork
portalNetworkDeprecated* {. networksDeprecated* {.
hidden, hidden,
desc: desc:
"DEPRECATED: The --network flag will be removed in the future, please use the drop in replacement --portal-network flag instead", "DEPRECATED: The --networks flag will be removed in the future, " &
defaultValue: none(PortalNetwork), "please use the drop in replacement --portal-subnetworks flag instead",
name: "network" defaultValue: {},
.}: Option[PortalNetwork.mainnet]
networks* {.
desc: "Select which networks (Portal sub-protocols) to enable",
defaultValue: {Network.history},
name: "networks" name: "networks"
.}: set[Network] .}: set[PortalSubnetwork]
portalSubnetworks* {.
desc: "Select which networks (Portal sub-protocols) to enable",
defaultValue: {PortalSubnetwork.history},
name: "portal-subnetworks"
.}: set[PortalSubnetwork]
# Note: This will add bootstrap nodes for both Discovery v5 network and each # Note: This will add bootstrap nodes for both Discovery v5 network and each
# enabled Portal network. No distinction is made on bootstrap nodes per # enabled Portal network. No distinction is made on bootstrap nodes per
@ -363,21 +362,23 @@ proc parseCmdArg*(T: type ClientConfig, p: string): T {.raises: [ValueError].} =
proc completeCmdArg*(T: type ClientConfig, val: string): seq[string] = proc completeCmdArg*(T: type ClientConfig, val: string): seq[string] =
return @[] return @[]
proc parseCmdArg*(T: type set[Network], p: string): T {.raises: [ValueError].} = proc parseCmdArg*(
var res: set[Network] = {} T: type set[PortalSubnetwork], p: string
): T {.raises: [ValueError].} =
var res: set[PortalSubnetwork] = {}
let values = p.split({' ', ','}) let values = p.split({' ', ','})
for value in values: for value in values:
let stripped = value.strip() let stripped = value.strip()
let network = let network =
try: try:
parseEnum[Network](stripped) parseEnum[PortalSubnetwork](stripped)
except ValueError: except ValueError:
raise newException(ValueError, "Invalid network: " & stripped) raise newException(ValueError, "Invalid network: " & stripped)
res.incl(network) res.incl(network)
res res
proc completeCmdArg*(T: type set[Network], val: string): seq[string] = proc completeCmdArg*(T: type set[PortalSubnetwork], val: string): seq[string] =
return @[] return @[]
chronicles.formatIt(InputDir): chronicles.formatIt(InputDir):

View File

@ -6,15 +6,14 @@ Connecting to the current Portal network is as easy as running following command
./build/fluffy --rpc ./build/fluffy --rpc
``` ```
This will connect to the public [Portal testnet](https://github.com/ethereum/portal-network-specs/blob/master/testnet.md#portal-network-testnet) This will connect to the public Portal mainnet which contains nodes of the different clients.
which contains nodes of the different clients.
!!! note !!! note
Default the Fluffy node will connect to the By default the Fluffy node will connect to the
[bootstrap nodes](https://github.com/ethereum/portal-network-specs/blob/master/testnet.md#bootnodes) of the public testnet. [bootstrap nodes](https://github.com/ethereum/portal-network-specs/blob/master/bootnodes.md#bootnodes-mainnet) of the public mainnet.
When testing locally the `--portal-network:none` option can be provided to avoid When testing locally the `--network:none` option can be provided to avoid
connecting to any of the testnet bootstrap nodes. connecting to any of the default bootstrap nodes.
The `--rpc` option will also enable the different JSON-RPC interfaces through The `--rpc` option will also enable the different JSON-RPC interfaces through
which you can access the Portal Network. which you can access the Portal Network.
@ -32,4 +31,3 @@ Fluffy also supports a small subset of the [Execution JSON-RPC API](https://ethe
<!-- TODO: Explain some of the more important cli options here? Or in a separate <!-- TODO: Explain some of the more important cli options here? Or in a separate
page? --> page? -->

View File

@ -35,7 +35,7 @@ import
./network/state/[state_network, state_content], ./network/state/[state_network, state_content],
./network/history/[history_network, history_content], ./network/history/[history_network, history_content],
./network/beacon/[beacon_init_loader, beacon_light_client], ./network/beacon/[beacon_init_loader, beacon_light_client],
./network/wire/[portal_stream, portal_protocol_config], ./network/wire/[portal_stream, portal_protocol_config, portal_protocol],
./eth_data/history_data_ssz_e2s, ./eth_data/history_data_ssz_e2s,
./database/content_db, ./database/content_db,
./version, ./version,
@ -101,24 +101,35 @@ proc run(config: PortalConf) {.raises: [CatchableError].} =
loadBootstrapFile(string config.bootstrapNodesFile, bootstrapRecords) loadBootstrapFile(string config.bootstrapNodesFile, bootstrapRecords)
bootstrapRecords.add(config.bootstrapNodes) bootstrapRecords.add(config.bootstrapNodes)
var portalNetwork: PortalNetwork let portalNetwork =
if config.portalNetworkDeprecated.isSome(): if config.portalNetworkDeprecated.isNone():
warn "DEPRECATED: The --network flag will be removed in the future, please use the drop in replacement --portal-network flag instead" config.network
portalNetwork = config.portalNetworkDeprecated.get()
else: else:
portalNetwork = config.portalNetwork warn "DEPRECATED: The --portal-network flag will be removed in the future, " &
"please use the drop in replacement --network flag instead"
config.portalNetworkDeprecated.get()
let portalSubnetworks =
if config.networksDeprecated == {}:
config.portalSubnetworks
else:
warn "DEPRECATED: The --networks flag will be removed in the future, " &
"please use the drop in replacement --portal-subnetworks flag instead"
config.networksDeprecated
case portalNetwork case portalNetwork
of mainnet: of PortalNetwork.none:
discard # don't connect to any network bootstrap nodes
of PortalNetwork.mainnet:
for enrURI in mainnetBootstrapNodes: for enrURI in mainnetBootstrapNodes:
var record: Record var record: Record
if fromURI(record, enrURI): if fromURI(record, enrURI):
bootstrapRecords.add(record) bootstrapRecords.add(record)
of testnet: of PortalNetwork.angelfood:
# TODO: add testnet repo with bootstrap file. for enrURI in angelfoodBootstrapNodes:
discard var record: Record
else: if fromURI(record, enrURI):
discard bootstrapRecords.add(record)
let let
discoveryConfig = discoveryConfig =
@ -210,9 +221,10 @@ proc run(config: PortalConf) {.raises: [CatchableError].} =
loadAccumulator() loadAccumulator()
historyNetwork = historyNetwork =
if Network.history in config.networks: if PortalSubnetwork.history in portalSubnetworks:
Opt.some( Opt.some(
HistoryNetwork.new( HistoryNetwork.new(
portalNetwork,
d, d,
db, db,
streamManager, streamManager,
@ -225,9 +237,10 @@ proc run(config: PortalConf) {.raises: [CatchableError].} =
Opt.none(HistoryNetwork) Opt.none(HistoryNetwork)
stateNetwork = stateNetwork =
if Network.state in config.networks: if PortalSubnetwork.state in portalSubnetworks:
Opt.some( Opt.some(
StateNetwork.new( StateNetwork.new(
portalNetwork,
d, d,
db, db,
streamManager, streamManager,
@ -243,12 +256,15 @@ proc run(config: PortalConf) {.raises: [CatchableError].} =
beaconLightClient = beaconLightClient =
# TODO: Currently disabled by default as it is not sufficiently polished. # TODO: Currently disabled by default as it is not sufficiently polished.
# Eventually this should be always-on functionality. # Eventually this should be always-on functionality.
if Network.beacon in config.networks and config.trustedBlockRoot.isSome(): if PortalSubnetwork.beacon in portalSubnetworks and
config.trustedBlockRoot.isSome():
let let
# Portal works only over mainnet data currently # Portal works only over mainnet data currently
# TODO: investigate this load network data function
networkData = loadNetworkData("mainnet") networkData = loadNetworkData("mainnet")
beaconDb = BeaconDb.new(networkData, config.dataDir / "db" / "beacon_db") beaconDb = BeaconDb.new(networkData, config.dataDir / "db" / "beacon_db")
beaconNetwork = BeaconNetwork.new( beaconNetwork = BeaconNetwork.new(
portalNetwork,
d, d,
beaconDb, beaconDb,
streamManager, streamManager,

View File

@ -23,8 +23,6 @@ export beacon_content, beacon_db
logScope: logScope:
topics = "beacon_network" topics = "beacon_network"
const lightClientProtocolId* = [byte 0x50, 0x1A]
type BeaconNetwork* = ref object type BeaconNetwork* = ref object
portalProtocol*: PortalProtocol portalProtocol*: PortalProtocol
beaconDb*: BeaconDb beaconDb*: BeaconDb
@ -183,6 +181,7 @@ proc getHistoricalSummaries*(
proc new*( proc new*(
T: type BeaconNetwork, T: type BeaconNetwork,
portalNetwork: PortalNetwork,
baseProtocol: protocol.Protocol, baseProtocol: protocol.Protocol,
beaconDb: BeaconDb, beaconDb: BeaconDb,
streamManager: StreamManager, streamManager: StreamManager,
@ -206,7 +205,7 @@ proc new*(
portalProtocol = PortalProtocol.new( portalProtocol = PortalProtocol.new(
baseProtocol, baseProtocol,
lightClientProtocolId, getProtocolId(portalNetwork, PortalSubnetwork.beacon),
toContentIdHandler, toContentIdHandler,
createGetHandler(beaconDb), createGetHandler(beaconDb),
stream, stream,

View File

@ -47,8 +47,6 @@ export accumulator
proc `$`(x: BlockHeader): string = proc `$`(x: BlockHeader): string =
$x $x
const historyProtocolId* = [byte 0x50, 0x0B]
type type
HistoryNetwork* = ref object HistoryNetwork* = ref object
portalProtocol*: PortalProtocol portalProtocol*: PortalProtocol
@ -703,6 +701,7 @@ proc validateContent(
proc new*( proc new*(
T: type HistoryNetwork, T: type HistoryNetwork,
portalNetwork: PortalNetwork,
baseProtocol: protocol.Protocol, baseProtocol: protocol.Protocol,
contentDB: ContentDB, contentDB: ContentDB,
streamManager: StreamManager, streamManager: StreamManager,
@ -718,7 +717,7 @@ proc new*(
portalProtocol = PortalProtocol.new( portalProtocol = PortalProtocol.new(
baseProtocol, baseProtocol,
historyProtocolId, getProtocolId(portalNetwork, PortalSubnetwork.history),
toContentIdHandler, toContentIdHandler,
createGetHandler(contentDB), createGetHandler(contentDB),
stream, stream,

View File

@ -33,8 +33,7 @@ const
#TODO currently we are using value for history network, but this should be #TODO currently we are using value for history network, but this should be
#caluculated per netowork basis #caluculated per netowork basis
maxItemsPerOfferBySize = getMaxOfferedContentKeys( maxItemsPerOfferBySize = getMaxOfferedContentKeys(
uint32(len(history_network.historyProtocolId)), uint32(len(PortalProtocolId)), uint32(history_content.maxContentKeySize)
uint32(history_content.maxContentKeySize),
) )
# Offering is restricted to max 64 items # Offering is restricted to max 64 items

View File

@ -26,8 +26,6 @@ export results, state_content
logScope: logScope:
topics = "portal_state" topics = "portal_state"
const stateProtocolId* = [byte 0x50, 0x0A]
type StateNetwork* = ref object type StateNetwork* = ref object
portalProtocol*: PortalProtocol portalProtocol*: PortalProtocol
contentDB*: ContentDB contentDB*: ContentDB
@ -41,6 +39,7 @@ func toContentIdHandler(contentKey: ByteList): results.Opt[ContentId] =
proc new*( proc new*(
T: type StateNetwork, T: type StateNetwork,
portalNetwork: PortalNetwork,
baseProtocol: protocol.Protocol, baseProtocol: protocol.Protocol,
contentDB: ContentDB, contentDB: ContentDB,
streamManager: StreamManager, streamManager: StreamManager,
@ -55,7 +54,7 @@ proc new*(
let portalProtocol = PortalProtocol.new( let portalProtocol = PortalProtocol.new(
baseProtocol, baseProtocol,
stateProtocolId, getProtocolId(portalNetwork, PortalSubnetwork.state),
toContentIdHandler, toContentIdHandler,
createGetHandler(contentDB), createGetHandler(contentDB),
s, s,

View File

@ -254,6 +254,41 @@ func init*(
nodesInterestedInContent: nodesInterestedInContent, nodesInterestedInContent: nodesInterestedInContent,
) )
func getProtocolId*(
network: PortalNetwork, subnetwork: PortalSubnetwork
): PortalProtocolId =
const portalPrefix = byte(0x50)
case network
of PortalNetwork.none, PortalNetwork.mainnet:
case subnetwork
of PortalSubnetwork.state:
[portalPrefix, 0x0A]
of PortalSubnetwork.history:
[portalPrefix, 0x0B]
of PortalSubnetwork.beacon:
[portalPrefix, 0x0C]
of PortalSubnetwork.transactionIndex:
[portalPrefix, 0x0D]
of PortalSubnetwork.verkleState:
[portalPrefix, 0x0E]
of PortalSubnetwork.transactionGossip:
[portalPrefix, 0x0F]
of PortalNetwork.angelfood:
case subnetwork
of PortalSubnetwork.state:
[portalPrefix, 0x4A]
of PortalSubnetwork.history:
[portalPrefix, 0x4B]
of PortalSubnetwork.beacon:
[portalPrefix, 0x4C]
of PortalSubnetwork.transactionIndex:
[portalPrefix, 0x4D]
of PortalSubnetwork.verkleState:
[portalPrefix, 0x4E]
of PortalSubnetwork.transactionGossip:
[portalPrefix, 0x4F]
func `$`(id: PortalProtocolId): string = func `$`(id: PortalProtocolId): string =
id.toHex() id.toHex()

View File

@ -10,6 +10,20 @@
import std/strutils, confutils, chronos, stint, eth/p2p/discoveryv5/routing_table import std/strutils, confutils, chronos, stint, eth/p2p/discoveryv5/routing_table
type type
PortalNetwork* = enum
none
mainnet
angelfood
# The Portal sub-protocols
PortalSubnetwork* = enum
state
history
beacon
transactionIndex
verkleState
transactionGossip
RadiusConfigKind* = enum RadiusConfigKind* = enum
Static Static
Dynamic Dynamic

View File

@ -44,6 +44,8 @@ const
# rlp.rawData() in the enr code. # rlp.rawData() in the enr code.
mainnetBootstrapNodes* = mainnetBootstrapNodes* =
loadCompileTimeBootstrapNodes(portalConfigDir / "bootstrap_nodes.txt") loadCompileTimeBootstrapNodes(portalConfigDir / "bootstrap_nodes.txt")
angelfoodBootstrapNodes* =
loadCompileTimeBootstrapNodes(portalConfigDir / "bootstrap_nodes_angelfood.txt")
finishedAccumulatorSSZ* = slurp(portalConfigDir / "finished_accumulator.ssz") finishedAccumulatorSSZ* = slurp(portalConfigDir / "finished_accumulator.ssz")

View File

@ -369,7 +369,6 @@ proc installEthApiHandlers*(
raise newException(ValueError, error) raise newException(ValueError, error)
balance = (await stateNetwork.get().getBalance(blockHash, data.EthAddress)).valueOr: balance = (await stateNetwork.get().getBalance(blockHash, data.EthAddress)).valueOr:
# Should we return 0 here or throw a more detailed error?
raise newException(ValueError, "Unable to get balance") raise newException(ValueError, "Unable to get balance")
return balance return balance
@ -397,7 +396,6 @@ proc installEthApiHandlers*(
nonce = ( nonce = (
await stateNetwork.get().getTransactionCount(blockHash, data.EthAddress) await stateNetwork.get().getTransactionCount(blockHash, data.EthAddress)
).valueOr: ).valueOr:
# Should we return 0 here or throw a more detailed error?
raise newException(ValueError, "Unable to get transaction count") raise newException(ValueError, "Unable to get transaction count")
return nonce.Quantity return nonce.Quantity
@ -425,7 +423,6 @@ proc installEthApiHandlers*(
slotValue = ( slotValue = (
await stateNetwork.get().getStorageAt(blockHash, data.EthAddress, slot) await stateNetwork.get().getStorageAt(blockHash, data.EthAddress, slot)
).valueOr: ).valueOr:
# Should we return 0 here or throw a more detailed error?
raise newException(ValueError, "Unable to get storage slot") raise newException(ValueError, "Unable to get storage slot")
return FixedBytes[32](slotValue.toBytesBE()) return FixedBytes[32](slotValue.toBytesBE())
@ -450,7 +447,6 @@ proc installEthApiHandlers*(
raise newException(ValueError, error) raise newException(ValueError, error)
bytecode = (await stateNetwork.get().getCode(blockHash, data.EthAddress)).valueOr: bytecode = (await stateNetwork.get().getCode(blockHash, data.EthAddress)).valueOr:
# Should we return empty sequence here or throw a more detailed error?
raise newException(ValueError, "Unable to get code") raise newException(ValueError, "Unable to get code")
return bytecode.asSeq() return bytecode.asSeq()

View File

@ -9,7 +9,7 @@ import
chronos, chronos,
eth/p2p/discoveryv5/protocol as discv5_protocol, eth/p2p/discoveryv5/protocol as discv5_protocol,
beacon_chain/spec/forks, beacon_chain/spec/forks,
../../network/wire/[portal_protocol, portal_stream], ../../network/wire/[portal_protocol, portal_protocol_config, portal_stream],
../../network/beacon/[beacon_init_loader, beacon_network], ../../network/beacon/[beacon_init_loader, beacon_network],
../test_helpers ../test_helpers
@ -24,7 +24,8 @@ proc newLCNode*(
node = initDiscoveryNode(rng, PrivateKey.random(rng[]), localAddress(port)) node = initDiscoveryNode(rng, PrivateKey.random(rng[]), localAddress(port))
db = BeaconDb.new(networkData, "", inMemory = true) db = BeaconDb.new(networkData, "", inMemory = true)
streamManager = StreamManager.new(node) streamManager = StreamManager.new(node)
network = BeaconNetwork.new(node, db, streamManager, networkData.forks) network =
BeaconNetwork.new(PortalNetwork.none, node, db, streamManager, networkData.forks)
return BeaconNode(discoveryProtocol: node, beaconNetwork: network) return BeaconNode(discoveryProtocol: node, beaconNetwork: network)

View File

@ -148,8 +148,9 @@ proc newStateNode*(
node = initDiscoveryNode(rng, PrivateKey.random(rng[]), localAddress(port)) node = initDiscoveryNode(rng, PrivateKey.random(rng[]), localAddress(port))
db = ContentDB.new("", uint32.high, inMemory = true) db = ContentDB.new("", uint32.high, inMemory = true)
sm = StreamManager.new(node) sm = StreamManager.new(node)
hn = HistoryNetwork.new(node, db, sm, FinishedAccumulator()) hn = HistoryNetwork.new(PortalNetwork.none, node, db, sm, FinishedAccumulator())
sn = StateNetwork.new(node, db, sm, historyNetwork = Opt.some(hn)) sn =
StateNetwork.new(PortalNetwork.none, node, db, sm, historyNetwork = Opt.some(hn))
return StateNode(discoveryProtocol: node, stateNetwork: sn) return StateNode(discoveryProtocol: node, stateNetwork: sn)

View File

@ -28,7 +28,8 @@ proc newHistoryNode(
node = initDiscoveryNode(rng, PrivateKey.random(rng[]), localAddress(port)) node = initDiscoveryNode(rng, PrivateKey.random(rng[]), localAddress(port))
db = ContentDB.new("", uint32.high, inMemory = true) db = ContentDB.new("", uint32.high, inMemory = true)
streamManager = StreamManager.new(node) streamManager = StreamManager.new(node)
historyNetwork = HistoryNetwork.new(node, db, streamManager, accumulator) historyNetwork =
HistoryNetwork.new(PortalNetwork.none, node, db, streamManager, accumulator)
return HistoryNode(discoveryProtocol: node, historyNetwork: historyNetwork) return HistoryNode(discoveryProtocol: node, historyNetwork: historyNetwork)
@ -187,7 +188,7 @@ procSuite "History Content Network":
historyNode2.start() historyNode2.start()
let maxOfferedHistoryContent = let maxOfferedHistoryContent =
getMaxOfferedContentKeys(uint32(len(historyProtocolId)), maxContentKeySize) getMaxOfferedContentKeys(uint32(len(PortalProtocolId)), maxContentKeySize)
let headersWithProof = let headersWithProof =
buildHeadersWithProof(headers[0 .. maxOfferedHistoryContent], epochAccumulators) buildHeadersWithProof(headers[0 .. maxOfferedHistoryContent], epochAccumulators)

View File

@ -119,7 +119,7 @@ type
.}: Port .}: Port
protocolId* {. protocolId* {.
defaultValue: historyProtocolId, defaultValue: getProtocolId(PortalNetwork.mainnet, PortalSubnetwork.history),
desc: "Portal wire protocol id for the network to connect to", desc: "Portal wire protocol id for the network to connect to",
name: "protocol-id" name: "protocol-id"
.}: PortalProtocolId .}: PortalProtocolId

@ -1 +1 @@
Subproject commit 0f18d18c1a1ce75d751dee3a440a5a5fcc0ac89e Subproject commit 52d206cdadae04c4faa204d3deb63cf1beb215ea