diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cfbead39ea..91476aad78 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,6 +107,13 @@ jobs: # for miniupnp that runs "wingenminiupnpcstrings.exe" from the current dir echo "." >> $GITHUB_PATH + - name: Install nasm (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + choco install nasm --no-progress -y + "C:\Program Files\NASM" | Out-File -FilePath $Env:GITHUB_PATH -Encoding utf8 -Append + - name: Derive environment variables run: | if [[ '${{ matrix.target.cpu }}' == 'amd64' ]]; then diff --git a/.gitmodules b/.gitmodules index d99ce2e7f4..917ec8f97f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -237,3 +237,6 @@ path = vendor/nim-quic url = https://github.com/vacp2p/nim-quic branch = main +[submodule "vendor/nim-lsquic"] + path = vendor/nim-lsquic + url = https://github.com/vacp2p/nim-lsquic.git diff --git a/Makefile b/Makefile index d8af5359b6..572a85c4af 100644 --- a/Makefile +++ b/Makefile @@ -91,6 +91,7 @@ TOOLS_CSV := $(subst $(SPACE),$(COMMA),$(TOOLS)) test \ clean \ libbacktrace \ + boringssl-win64 \ book \ publish-book \ dist-amd64 \ @@ -164,7 +165,7 @@ ifeq ($(USE_LIBBACKTRACE), 0) NIM_PARAMS += -d:disable_libbacktrace endif -deps: | deps-common nat-libs build/generate_makefile +deps: | deps-common nat-libs build/generate_makefile boringssl-win64 ifneq ($(USE_LIBBACKTRACE), 0) deps: | libbacktrace endif @@ -178,6 +179,9 @@ update: | update-common libbacktrace: + "$(MAKE)" -C vendor/nim-libbacktrace --no-print-directory BUILD_CXX_LIB=0 +boringssl-win64: + + "$(MAKE)" -C vendor/nim-lsquic + # Make sure ports don't overlap to support concurrent execution of tests # Avoid selecting ephemeral ports that may be used by others; safe = 5001-9999 # - Port 8301 is used by Consul @@ -193,11 +197,13 @@ libbacktrace: # # REST tests: # - --base-port (REST_TEST_BASE_PORT + 0) -# - --base-rest-port (REST_TEST_BASE_PORT + 1) -# - --base-metrics-port (REST_TEST_BASE_PORT + 2) +# - debug-quic-port (REST_TEST_BASE_PORT + 1) +# - --base-rest-port (REST_TEST_BASE_PORT + 2) +# - --base-metrics-port (REST_TEST_BASE_PORT + 3) # # Local testnets (entire continuous range): # - --base-port + [0, --nodes + --light-clients) +# - debug-quic-port uses (--base-port + 1) + [0, --nodes + --light-clients) # - --base-rest-port + [0, --nodes) # - --base-metrics-port + [0, --nodes) # - --base-vc-keymanager-port + [0, --nodes) @@ -218,9 +224,9 @@ MAINNET_TESTNET_BASE_PORT := 26501 restapi-test: ./tests/simulation/restapi.sh \ --data-dir resttest0_data \ - --base-port $$(( $(REST_TEST_BASE_PORT) + EXECUTOR_NUMBER * 3 + 0 )) \ - --base-rest-port $$(( $(REST_TEST_BASE_PORT) + EXECUTOR_NUMBER * 3 + 1 )) \ - --base-metrics-port $$(( $(REST_TEST_BASE_PORT) + EXECUTOR_NUMBER * 3 + 2 )) \ + --base-port $$(( $(REST_TEST_BASE_PORT) + EXECUTOR_NUMBER * 4 + 0 )) \ + --base-rest-port $$(( $(REST_TEST_BASE_PORT) + EXECUTOR_NUMBER * 4 + 2 )) \ + --base-metrics-port $$(( $(REST_TEST_BASE_PORT) + EXECUTOR_NUMBER * 4 + 3 )) \ --resttest-delay 30 \ --kill-old-processes @@ -500,6 +506,8 @@ nimbus_beacon_node: force_build_alone_tools GOERLI_TESTNETS_PARAMS := \ --tcp-port=$$(( $(BASE_PORT) + $(NODE_ID) )) \ + --debug-quic=true \ + --debug-quic-port=$$(( $(BASE_PORT) + $(NODE_ID) + 1 )) \ --udp-port=$$(( $(BASE_PORT) + $(NODE_ID) )) \ --metrics \ --metrics-port=$$(( $(BASE_METRICS_PORT) + $(NODE_ID) )) \ diff --git a/beacon_chain/conf.nim b/beacon_chain/conf.nim index 2db03a2c57..28dedb69a6 100644 --- a/beacon_chain/conf.nim +++ b/beacon_chain/conf.nim @@ -36,7 +36,7 @@ from consensus_object_pools/block_pools_types_light_client export uri, nat, enr, - defaultEth2TcpPort, enabledLogLevel, + defaultEth2TcpPort, defaultEth2QuicPort, enabledLogLevel, defs, parseCmdArg, completeCmdArg, network_metadata, el_conf, network, confTomlDefs, confTomlNet, confTomlUri, jsnet, @@ -299,6 +299,19 @@ type defaultValueDesc: $defaultEth2TcpPortDesc name: "tcp-port" .}: Port + quicEnabled* {. + hidden + desc: "Enable QUIC transport" + defaultValue: true # TODO: set to false by default + name: "debug-quic" .}: bool + + quicPort* {. + hidden + desc: "Listening UDP port for Ethereum LibP2P traffic over QUIC" + defaultValue: defaultEth2QuicPort + defaultValueDesc: $defaultEth2QuicPortDesc + name: "debug-quic-port" .}: Port + udpPort* {. desc: "Listening UDP port for node discovery" defaultValue: defaultEth2TcpPort @@ -811,6 +824,11 @@ type desc: "External UDP port" name: "udp-port" .}: Port + quicPortExt* {. + hidden + desc: "External QUIC port" + name: "debug-quic-port" .}: Port + seqNumber* {. desc: "Record sequence number" defaultValue: 1, diff --git a/beacon_chain/conf_light_client.nim b/beacon_chain/conf_light_client.nim index 8a7752c5c1..5e7bd2e60c 100644 --- a/beacon_chain/conf_light_client.nim +++ b/beacon_chain/conf_light_client.nim @@ -69,6 +69,19 @@ type LightClientConf* = object defaultValueDesc: $defaultEth2TcpPortDesc name: "tcp-port" .}: Port + quicEnabled* {. + hidden + desc: "Enable QUIC transport" + defaultValue: true # TODO: set to false by default + name: "debug-quic" .}: bool + + quicPort* {. + hidden + desc: "Listening UDP port for Ethereum LibP2P traffic over QUIC" + defaultValue: defaultEth2QuicPort + defaultValueDesc: $defaultEth2QuicPortDesc + name: "debug-quic-port" .}: Port + udpPort* {. desc: "Listening UDP port for node discovery" defaultValue: defaultEth2TcpPort diff --git a/beacon_chain/networking/eth2_discovery.nim b/beacon_chain/networking/eth2_discovery.nim index baf14d7f1e..57f86f4840 100644 --- a/beacon_chain/networking/eth2_discovery.nim +++ b/beacon_chain/networking/eth2_discovery.nim @@ -12,6 +12,7 @@ import chronos, chronicles, eth/p2p/discoveryv5/[protocol, node, random2], ../spec/datatypes/[altair, fulu], + ../spec/network, ../spec/eth2_ssz_serialization, ".."/[conf, conf_light_client] @@ -78,7 +79,7 @@ proc loadBootstrapFile*(bootstrapFile: string, proc new*(T: type Eth2DiscoveryProtocol, config: BeaconNodeConf | LightClientConf, - enrIp: Opt[IpAddress], enrTcpPort, enrUdpPort: Opt[Port], + enrIp: Opt[IpAddress], enrTcpPort, enrQuicPort, enrUdpPort: Opt[Port], pk: PrivateKey, enrFields: openArray[(string, seq[byte])], rng: ref HmacDrbgContext): T = @@ -102,8 +103,8 @@ proc new*(T: type Eth2DiscoveryProtocol, else: Opt.none(IpAddress) - newProtocol(pk, enrIp, enrTcpPort, enrUdpPort, enrFields, bootstrapEnrs, - bindPort = config.udpPort, bindIp = listenAddress, + newProtocol(pk, enrIp, enrTcpPort, enrUdpPort, enrQuicPort, enrFields, + bootstrapEnrs, bindPort = config.udpPort, bindIp = listenAddress, enrAutoUpdate = config.enrAutoUpdate, rng = rng) func isCompatibleForkId*(discoveryForkId: ENRForkID, peerForkId: ENRForkID): bool = diff --git a/beacon_chain/networking/eth2_network.nim b/beacon_chain/networking/eth2_network.nim index 531ce04848..37b2a7f117 100644 --- a/beacon_chain/networking/eth2_network.nim +++ b/beacon_chain/networking/eth2_network.nim @@ -228,6 +228,13 @@ type NetRes*[T] = Result[T, Eth2NetworkingError] ## This is type returned from all network requests + ## + + PeerAddrProto* {.pure.} = enum + TCP + UDP + QUIC + const clientId* = "Nimbus beacon node " & fullVersionStr @@ -1320,8 +1327,20 @@ proc handleIncomingStream(network: Eth2Node, await noCancel conn.closeWithEOF() releasePeer(peer) +template tcpEndPoint(address, port): auto = + MultiAddress.init(address, tcpProtocol, port) + +template udpEndPoint(address, port): auto = + MultiAddress.init(address, udpProtocol, port) + +template quicEndPoint(address, port): auto = + try: + MultiAddress.init(address, udpProtocol, port) & MultiAddress.init("/quic-v1").tryGet() + except LPError: + raiseAssert "invalid quic address" + func toPeerAddr*(r: enr.TypedRecord, - proto: IpTransportProtocol): Result[PeerAddr, cstring] = + peerAddrProto: seq[PeerAddrProto]): Result[PeerAddr, cstring] = if not r.secp256k1.isSome: return err("enr: no secp256k1 key in record") @@ -1332,42 +1351,61 @@ func toPeerAddr*(r: enr.TypedRecord, var addrs = newSeq[MultiAddress]() - case proto - of tcpProtocol: - if r.ip.isSome and r.tcp.isSome: - let ip = IpAddress( - family: IpAddressFamily.IPv4, - address_v4: r.ip.get) - addrs.add MultiAddress.init(ip, tcpProtocol, Port r.tcp.get) - - if r.ip6.isSome: - let ip = IpAddress( - family: IpAddressFamily.IPv6, - address_v6: r.ip6.get) - if r.tcp6.isSome: - addrs.add MultiAddress.init(ip, tcpProtocol, Port r.tcp6.get) - elif r.tcp.isSome: - addrs.add MultiAddress.init(ip, tcpProtocol, Port r.tcp.get) - else: - discard - - of udpProtocol: - if r.ip.isSome and r.udp.isSome: - let ip = IpAddress( - family: IpAddressFamily.IPv4, - address_v4: r.ip.get) - addrs.add MultiAddress.init(ip, udpProtocol, Port r.udp.get) - - if r.ip6.isSome: - let ip = IpAddress( - family: IpAddressFamily.IPv6, - address_v6: r.ip6.get) - if r.udp6.isSome: - addrs.add MultiAddress.init(ip, udpProtocol, Port r.udp6.get) - elif r.udp.isSome: - addrs.add MultiAddress.init(ip, udpProtocol, Port r.udp.get) - else: - discard + for proto in peerAddrProto: + case proto + of PeerAddrProto.TCP: + if r.ip.isSome and r.tcp.isSome: + let ip = IpAddress( + family: IpAddressFamily.IPv4, + address_v4: r.ip.get) + addrs.add tcpEndpoint(ip, Port r.tcp.get) + + if r.ip6.isSome: + let ip = IpAddress( + family: IpAddressFamily.IPv6, + address_v6: r.ip6.get) + if r.tcp6.isSome: + addrs.add tcpEndpoint(ip, Port r.tcp6.get) + elif r.tcp.isSome: + addrs.add tcpEndpoint(ip, Port r.tcp.get) + else: + discard + + of PeerAddrProto.UDP: + if r.ip.isSome and r.udp.isSome: + let ip = IpAddress( + family: IpAddressFamily.IPv4, + address_v4: r.ip.get) + addrs.add udpEndpoint(ip, Port r.udp.get) + + if r.ip6.isSome: + let ip = IpAddress( + family: IpAddressFamily.IPv6, + address_v6: r.ip6.get) + if r.udp6.isSome: + addrs.add udpEndpoint(ip, Port r.udp6.get) + elif r.udp.isSome: + addrs.add udpEndpoint(ip, Port r.udp.get) + else: + discard + + of PeerAddrProto.QUIC: + if r.ip.isSome and r.quic.isSome: + let ip = IpAddress( + family: IpAddressFamily.IPv4, + address_v4: r.ip.get) + addrs.add quicEndPoint(ip, Port r.quic.get) + + if r.ip6.isSome: + let ip = IpAddress( + family: IpAddressFamily.IPv6, + address_v6: r.ip6.get) + if r.quic6.isSome: + addrs.add quicEndPoint(ip, Port r.quic6.get) + elif r.quic.isSome: + addrs.add quicEndPoint(ip, Port r.quic.get) + else: + discard if addrs.len == 0: return err("enr: no addresses in record") @@ -1440,7 +1478,7 @@ proc connectWorker(node: Eth2Node, index: int) {.async: (raises: [CancelledError func toPeerAddr(node: Node): Result[PeerAddr, cstring] = let nodeRecord = TypedRecord.fromRecord(node.record) - let peerAddr = ? nodeRecord.toPeerAddr(tcpProtocol) + let peerAddr = ? nodeRecord.toPeerAddr(@[PeerAddrProto.TCP, PeerAddrProto.QUIC]) ok(peerAddr) proc trimConnections(node: Eth2Node, count: int) = @@ -1836,7 +1874,7 @@ proc new(T: type Eth2Node, enrForkId: ENRForkID, discoveryForkId: ENRForkID, forkDigests: ref ForkDigests, getBeaconTime: GetBeaconTimeFn, switch: Switch, pubsub: GossipSub, - ip: Opt[IpAddress], tcpPort, udpPort: Opt[Port], + ip: Opt[IpAddress], tcpPort, quicPort, udpPort: Opt[Port], privKey: keys.PrivateKey, discovery: bool, directPeers: DirectPeers, announcedAddresses: openArray[MultiAddress], rng: ref HmacDrbgContext): T = @@ -1871,7 +1909,7 @@ proc new(T: type Eth2Node, forkDigests: forkDigests, getBeaconTime: getBeaconTime, discovery: Eth2DiscoveryProtocol.new( - config, ip, tcpPort, udpPort, privKey, + config, ip, tcpPort, quicPort, udpPort, privKey, { enrForkIdField: SSZ.encode(enrForkId), enrAttestationSubnetsField: SSZ.encode(metadata.attnets) @@ -1930,7 +1968,7 @@ proc startListening*(node: Eth2Node) {.async.} = try: await node.switch.start() except CatchableError as exc: - fatal "Failed to start LibP2P transport. TCP port may be already in use", + fatal "Failed to start LibP2P transport. TCP/QUIC port may be already in use", exc = exc.msg quit 1 @@ -1954,7 +1992,7 @@ proc start*(node: Eth2Node) {.async: (raises: [CancelledError]).} = notice "Discovery disabled; trying bootstrap nodes", nodes = node.discovery.bootstrapRecords.len for enr in node.discovery.bootstrapRecords: - let pa = TypedRecord.fromRecord(enr).toPeerAddr(tcpProtocol) + let pa = TypedRecord.fromRecord(enr).toPeerAddr(@[PeerAddrProto.TCP, PeerAddrProto.QUIC]) if pa.isOk(): await node.connQueue.addLast(pa.get()) node.peerPingerHeartbeatFut = node.peerPingerHeartbeat() @@ -2228,9 +2266,6 @@ proc peerTrimmerHeartbeat(node: Eth2Node) {.async: (raises: [CancelledError]).} func asEthKey*(key: PrivateKey): keys.PrivateKey = keys.PrivateKey(key.skkey) -template tcpEndPoint(address, port): auto = - MultiAddress.init(address, tcpProtocol, port) - func initNetKeys(privKey: PrivateKey): NetKeyPair = let pubKey = privKey.getPublicKey().expect("working public key from random") NetKeyPair(seckey: privKey, pubkey: pubKey) @@ -2327,7 +2362,7 @@ func gossipId( proc newBeaconSwitch( config: BeaconNodeConf | LightClientConf, seckey: PrivateKey, - address: MultiAddress, + addresses: seq[MultiAddress], rng: ref HmacDrbgContext, ): Result[Switch, string] = let service: Service = WildcardAddressResolverService.new() @@ -2335,17 +2370,22 @@ proc newBeaconSwitch( var sb = SwitchBuilder.new() # Order of multiplexers matters, the first will be default try: - ok sb + sb = sb .withPrivateKey(seckey) - .withAddress(address) + .withAddresses(addresses) .withRng(rng) .withNoise() - .withMplex(chronos.minutes(5), chronos.minutes(5)) + # TODO: uncomment the following two lines to enable TCP back + #.withMplex(chronos.minutes(5), chronos.minutes(5)) + #.withTcpTransport({ServerFlags.ReuseAddr}) .withMaxConnections(config.maxPeers) .withAgentVersion(config.agentString) - .withTcpTransport({ServerFlags.ReuseAddr}) .withServices(@[service]) - .build() + + if config.quicEnabled: + sb = sb.withQuicTransport() + + ok sb.build() except LPError as exc: err(exc.msg) @@ -2369,9 +2409,20 @@ proc createEth2Node*( else: getAutoAddress(Port(0)).toIpAddress() - (extIp, extTcpPort, extUdpPort) = - setupAddress(config.nat, listenAddress, config.tcpPort, - config.udpPort, clientId) + var ports = newSeq[PortSpec]() + ports.add((config.tcpPort, PortProtocol.TCP)) + ports.add((config.udpPort, PortProtocol.UDP)) + if config.quicEnabled: + ports.add((config.quicPort, PortProtocol.UDP)) + + let + (extIp, extPorts) = setupAddress(config.nat, listenAddress, ports, clientId) + + # TODO: uncommment this line and remove the next to add back TCP support + extTcpPort = Opt.none(Port) + # extTcpPort = extPorts[0].toPort() + extUdpPort = extPorts[1].toPort() + extQuicPort = if config.quicEnabled: extPorts[2].toPort() else: Opt.none(Port) directPeers = block: var res: DirectPeers @@ -2383,7 +2434,7 @@ proc createEth2Node*( warn "Failed to parse direct peer address, skipping", enr=s, err = error return err("Invalid direct peer") typedEnr = TypedRecord.fromRecord(enr) - peerAddress = toPeerAddr(typedEnr, tcpProtocol).get() + peerAddress = toPeerAddr(typedEnr, @[PeerAddrProto.TCP, PeerAddrProto.QUIC]).get() (peerAddress.peerId, peerAddress.addrs[0]) elif s.startsWith("/"): parseFullAddress(s).valueOr: @@ -2396,10 +2447,15 @@ proc createEth2Node*( info "Adding privileged direct peer", peerId, address res - hostAddress = tcpEndPoint(listenAddress, config.tcpPort) - announcedAddresses = - if extIp.isNone() or extTcpPort.isNone(): @[] - else: @[tcpEndPoint(extIp.get(), extTcpPort.get())] + var hostAddress = @[tcpEndPoint(listenAddress, config.tcpPort)] + + var announcedAddresses = newSeq[Multiaddress]() + # TODO: uncomment the following lines to add back TCP support + #if not(extIp.isNone() or extTcpPort.isNone()): + # announcedAddresses.add tcpEndPoint(extIp.get(), extTcpPort.get().port) + if config.quicEnabled and not(extIp.isNone() or extQuicPort.isNone()): + hostAddress.add(quicEndpoint(listenAddress, config.quicPort)) + announcedAddresses.add(quicEndpoint(extIp.get(), extQuicPort.get())) debug "Initializing networking", hostAddress, network_public_key = netKeys.pubkey, @@ -2478,7 +2534,7 @@ proc createEth2Node*( let node = Eth2Node.new( config, cfg, enrForkId, discoveryForkId, forkDigests, getBeaconTime, switch, pubsub, extIp, - extTcpPort, extUdpPort, netKeys.seckey.asEthKey, + extTcpPort, extQuicPort, extUdpPort, netKeys.seckey.asEthKey, discovery = config.discv5Enabled, directPeers, announcedAddresses, rng = rng) diff --git a/beacon_chain/nimbus_beacon_node.nim b/beacon_chain/nimbus_beacon_node.nim index 2c3497b0e0..ce0d9d10a1 100644 --- a/beacon_chain/nimbus_beacon_node.nim +++ b/beacon_chain/nimbus_beacon_node.nim @@ -2880,6 +2880,7 @@ proc doRecord(config: BeaconNodeConf, rng: var HmacDrbgContext) {. Opt.some(config.ipExt), Opt.some(config.tcpPortExt), Opt.some(config.udpPortExt), + if config.quicEnabled: Opt.some(config.quicPortExt) else: Opt.none(Port), fieldPairs).expect("Record within size limits") echo record.toURI() diff --git a/beacon_chain/rpc/rest_node_api.nim b/beacon_chain/rpc/rest_node_api.nim index 95e2438636..bbbcaef0c0 100644 --- a/beacon_chain/rpc/rest_node_api.nim +++ b/beacon_chain/rpc/rest_node_api.nim @@ -120,7 +120,7 @@ proc getLastSeenAddress(node: BeaconNode, id: PeerId): string = proc getDiscoveryAddresses(node: BeaconNode): seq[string] = let typedRec = TypedRecord.fromRecord(node.network.enrRecord()) - peerAddr = typedRec.toPeerAddr(udpProtocol).valueOr: + peerAddr = typedRec.toPeerAddr(@[PeerAddrProto.UDP]).valueOr: return default(seq[string]) maddress = MultiAddress.init(multiCodec("p2p"), peerAddr.peerId).valueOr: return default(seq[string]) diff --git a/beacon_chain/spec/network.nim b/beacon_chain/spec/network.nim index 7dda9c1b2c..e8b212e4ea 100644 --- a/beacon_chain/spec/network.nim +++ b/beacon_chain/spec/network.nim @@ -43,6 +43,9 @@ const defaultEth2TcpPort* = 9000 defaultEth2TcpPortDesc* = $defaultEth2TcpPort + defaultEth2QuicPort* = 9001 + defaultEth2QuicPortDesc* = $defaultEth2QuicPort + # This is not part of the spec! But it's port which Lighthouse uses defaultEth2RestPort* = 5052 defaultEth2RestPortDesc* = $defaultEth2RestPort @@ -52,6 +55,7 @@ const enrCustodySubnetCountField* = "cgc" enrNextForkDigestField* = "nfd" enrForkIdField* = "eth2" + quicField* = "quic" template eth2Prefix(forkDigest: ForkDigest): string = "/eth2/" & $forkDigest & "/" diff --git a/config.nims b/config.nims index 51d210879e..97348a25e6 100644 --- a/config.nims +++ b/config.nims @@ -66,8 +66,17 @@ if defined(limitStackUsage): # available on some GCC versions but not all - run with `-d:limitStackUsage` # and look for .su files in "./build/", "./nimcache/" or $TMPDIR that list the # stack size of each function. - switch("passC", "-fstack-usage -Werror=stack-usage=1048576") - switch("passL", "-fstack-usage -Werror=stack-usage=1048576") + + # TODO: + # 2025-12-10T16:43:27.1475097Z /github-runner/github-runner-node-02/workspace/nimbus-eth2/nimbus-eth2/vendor/nim-lsquic/libs/lsquic/src/liblsquic/lsquic_hkdf.c: In function ‘lsquic_qhkdf_expand’: + # 2025-12-10T16:43:27.1477049Z /github-runner/github-runner-node-02/workspace/nimbus-eth2/nimbus-eth2/vendor/nim-lsquic/libs/lsquic/src/liblsquic/lsquic_hkdf.c:13:1: error: stack usage might be unbounded [-Werror=stack-usage=] + # 2025-12-10T16:43:27.1478294Z 13 | lsquic_qhkdf_expand (const EVP_MD *md, const unsigned char *secret, + # 2025-12-10T16:43:27.1478769Z | ^ + # 2025-12-10T16:43:28.4943148Z /github-runner/github-runner-node-02/workspace/nimbus-eth2/nimbus-eth2/vendor/nim-lsquic/libs/lsquic/src/liblsquic/lsquic_handshake.c: In function ‘lsquic_enc_session_handle_chlo’: + # 2025-12-10T16:43:28.4946439Z /github-runner/github-runner-node-02/workspace/nimbus-eth2/nimbus-eth2/vendor/nim-lsquic/libs/lsquic/src/liblsquic/lsquic_handshake.c:3298:1: error: stack usage might be unbounded [-Werror=stack-usage=] + #switch("passC", "-fstack-usage -Werror=stack-usage=1048576") + #switch("passL", "-fstack-usage -Werror=stack-usage=1048576") + discard if defined(windows): # disable timestamps in Windows PE headers - https://wiki.debian.org/ReproducibleBuilds/TimestampsInPEBinaries diff --git a/docker/dist/README.md.tpl b/docker/dist/README.md.tpl index 07cd43f0f6..22a29e6a8c 100644 --- a/docker/dist/README.md.tpl +++ b/docker/dist/README.md.tpl @@ -42,7 +42,7 @@ To connect to mainnet with default options: The script will forward all supplied options to the beacon node executable: ```bash -./run-mainnet-beacon-node.sh --log-level=DEBUG --tcp-port=9050 +./run-mainnet-beacon-node.sh --log-level=DEBUG --tcp-port=9050 --debug-quic=true --debug-quic-port=9051 ``` To monitor the Eth1 validator deposit contract, you'll need to pair diff --git a/docker/dist/binaries/docker-compose-example1.yml b/docker/dist/binaries/docker-compose-example1.yml index 32d8415d35..76c07fcd9f 100644 --- a/docker/dist/binaries/docker-compose-example1.yml +++ b/docker/dist/binaries/docker-compose-example1.yml @@ -15,11 +15,12 @@ services: ports: - 9000:9000/tcp - 9000:9000/udp + - 9001:9001/udp - 127.0.0.1:5052:5052/tcp - 127.0.0.1:8008:8008/tcp volumes: - ./data:/home/user/nimbus-eth2/build/data - # you need to make sure that port 9000 is accesible from outside; no automagic port forwarding here + # you need to make sure that ports 9000/9001 are accesible from outside; no automagic port forwarding here command: >- --network=hoodi --data-dir=/home/user/nimbus-eth2/build/data/shared_hoodi_0 @@ -28,6 +29,8 @@ services: --log-level=info --tcp-port=9000 --udp-port=9000 + --debug-quic=true + --debug-quic-port=9001 --rest --rest-address=0.0.0.0 --rest-port=5052 diff --git a/ncli/ncli_testnet.nim b/ncli/ncli_testnet.nim index 38914c9a0f..e74590505f 100644 --- a/ncli/ncli_testnet.nim +++ b/ncli/ncli_testnet.nim @@ -340,7 +340,7 @@ proc createEnr(rng: var HmacDrbgContext, Opt.some(address), Opt.some(port), Opt.some(port), - [ + extraFields = [ toFieldPair(enrForkIdField, forkId), toFieldPair(enrAttestationSubnetsField, SSZ.encode(netMetadata.attnets)) ]) diff --git a/scripts/launch_local_testnet.sh b/scripts/launch_local_testnet.sh index bd7d0e0c52..394eb1f83c 100755 --- a/scripts/launch_local_testnet.sh +++ b/scripts/launch_local_testnet.sh @@ -439,6 +439,16 @@ kill_by_port() { exit 1 fi done + for PID in $(lsof -n -i udp:${PORT} -t); do + echo -n "Found old process using UDP port ${PORT}, with PID ${PID}. " + if [[ "${KILL_OLD_PROCESSES}" == "1" ]]; then + echo "Killing it." + kill -SIGKILL "${PID}" || true + else + echo "Aborting." + exit 1 + fi + done done } @@ -515,7 +525,7 @@ if [[ "${OS}" != "windows" ]]; then # Stop Nimbus CL nodes for NUM_NODE in $(seq 1 $NUM_NODES); do - for PORT in $(( BASE_PORT + NUM_NODE - 1 )) $(( BASE_METRICS_PORT + NUM_NODE - 1)) $(( BASE_REST_PORT + NUM_NODE - 1)); do + for PORT in $(( BASE_PORT + NUM_NODE - 1 )) $(( BASE_PORT + 2000 + NUM_NODE - 1 )) $(( BASE_METRICS_PORT + NUM_NODE - 1)) $(( BASE_REST_PORT + NUM_NODE - 1)); do PORTS_TO_KILL+=("${PORT}") done done @@ -1136,6 +1146,8 @@ for NUM_NODE in $(seq 1 "${NUM_NODES}"); do --config-file="${CLI_CONF_FILE}" \ --tcp-port=$(( BASE_PORT + NUM_NODE - 1 )) \ --udp-port=$(( BASE_PORT + NUM_NODE - 1 )) \ + --debug-quic=true \ + --debug-quic-port=$(( BASE_PORT + 2000 + NUM_NODE - 1 )) \ --max-peers=$(( NUM_NODES + LC_NODES - 1 )) \ --data-dir="${CONTAINER_NODE_DATA_DIR}" \ ${BOOTSTRAP_ARG} \ @@ -1254,6 +1266,9 @@ if [ "$LC_NODES" -ge "1" ]; then WEB3_ARG+=("--web3-url=http://127.0.0.1:${GETH_AUTH_RPC_PORTS[$(( NUM_NODES + NUM_LC - 1 ))]}") fi + TCP_PORT=$(( BASE_PORT + NUM_NODES + NUM_LC - 1 )) + QUIC_PORT=$(( TCP_PORT + 1000 )) + ./build/nimbus_light_client \ --log-level="${LOG_LEVEL}" \ --log-format="json" \ @@ -1262,6 +1277,8 @@ if [ "$LC_NODES" -ge "1" ]; then --bootstrap-node="${LC_BOOTSTRAP_NODE}" \ --tcp-port=$(( BASE_PORT + NUM_NODES + NUM_LC - 1 )) \ --udp-port=$(( BASE_PORT + NUM_NODES + NUM_LC - 1 )) \ + --debug-quic=true \ + --debug-quic-port=$(( BASE_PORT + 2000 + NUM_NODES + NUM_LC - 1 )) \ --max-peers=$(( NUM_NODES + LC_NODES - 1 )) \ --nat="extip:127.0.0.1" \ --trusted-block-root="${LC_TRUSTED_BLOCK_ROOT}" \ diff --git a/scripts/run-beacon-node.sh b/scripts/run-beacon-node.sh index f3976f4d53..d977c38989 100755 --- a/scripts/run-beacon-node.sh +++ b/scripts/run-beacon-node.sh @@ -60,12 +60,17 @@ if [[ "$WEB3_URL" != "" ]]; then WEB3_URL_ARG="--web3-url=${WEB3_URL}" fi +TCP_PORT=$(( BASE_P2P_PORT + NODE_ID )) +QUIC_PORT=$(( TCP_PORT + 1 )) + # Allow the binary to receive signals directly. exec ${WINPTY} build/${NBC_BINARY} \ --network=${NETWORK} \ --data-dir="${DATA_DIR}" \ - --tcp-port=$(( ${BASE_P2P_PORT} + ${NODE_ID} )) \ - --udp-port=$(( ${BASE_P2P_PORT} + ${NODE_ID} )) \ + --tcp-port=${TCP_PORT} \ + --udp-port=${TCP_PORT} \ + --debug-quic=true \ + --debug-quic-port=${QUIC_PORT} \ --rest \ --rest-port=$(( ${BASE_REST_PORT} + ${NODE_ID} )) \ --metrics \ diff --git a/tests/simulation/restapi.sh b/tests/simulation/restapi.sh index eab7c23744..30423c512e 100755 --- a/tests/simulation/restapi.sh +++ b/tests/simulation/restapi.sh @@ -145,7 +145,7 @@ fi # kill lingering processes from a previous run if [[ "${HAVE_LSOF}" == "1" ]]; then - for PORT in ${BASE_PORT} ${BASE_METRICS_PORT} ${BASE_REST_PORT}; do + for PORT in ${BASE_PORT} $((BASE_PORT + 2000)) ${BASE_METRICS_PORT} ${BASE_REST_PORT}; do for PID in $(lsof -n -i tcp:${PORT} -sTCP:LISTEN -t); do echo -n "Found old process listening on port ${PORT}, with PID ${PID}. " if [[ "${KILL_OLD_PROCESSES}" == "1" ]]; then @@ -156,6 +156,16 @@ if [[ "${HAVE_LSOF}" == "1" ]]; then exit 1 fi done + for PID in $(lsof -n -i udp:${PORT} -t); do + echo -n "Found old process using UDP port ${PORT}, with PID ${PID}. " + if [[ "${KILL_OLD_PROCESSES}" == "1" ]]; then + echo "Killing it." + kill -9 ${PID} || true + else + echo "Aborting." + exit 1 + fi + done done fi @@ -239,6 +249,8 @@ rm -rf "${TEST_DIR}/db" "${TEST_DIR}/validators/slashing_protection.sqlite3" ${NIMBUS_BEACON_NODE_BIN} \ --tcp-port=${BASE_PORT} \ --udp-port=${BASE_PORT} \ + --debug-quic=true \ + --debug-quic-port=$((BASE_PORT + 2000)) \ --log-level=${LOG_LEVEL:-DEBUG} \ --network="${TEST_DIR}" \ --data-dir="${TEST_DIR}" \ diff --git a/tests/test_keymanager_api.nim b/tests/test_keymanager_api.nim index 6548aa2f22..e62b2559a5 100644 --- a/tests/test_keymanager_api.nim +++ b/tests/test_keymanager_api.nim @@ -349,6 +349,8 @@ proc initBeaconNode(basePort: int): Future[BeaconNode] {.async: (raises: []).} = @[ "--tcp-port=" & $(basePort + PortKind.PeerToPeer.ord), "--udp-port=" & $(basePort + PortKind.PeerToPeer.ord), + "--debug-quic=true", + "--debug-quic-port=" & $(basePort + PortKind.PeerToPeer.ord + 2000), "--discv5=off", "--network=" & dataDir, "--data-dir=" & nodeDataDir, diff --git a/vendor/nim-eth b/vendor/nim-eth index 7f7aea1035..0edf3f4c01 160000 --- a/vendor/nim-eth +++ b/vendor/nim-eth @@ -1 +1 @@ -Subproject commit 7f7aea10355660b9770a56a69dce085f3a285af3 +Subproject commit 0edf3f4c0132ad7bc172055012ce13db899c06ce diff --git a/vendor/nim-libp2p b/vendor/nim-libp2p index aa8ce46f78..da3f968422 160000 --- a/vendor/nim-libp2p +++ b/vendor/nim-libp2p @@ -1 +1 @@ -Subproject commit aa8ce46f782240cb99a7222c474022b8cfd24e52 +Subproject commit da3f968422d3a82303d362213a34e1acd5a2f11c diff --git a/vendor/nim-lsquic b/vendor/nim-lsquic new file mode 160000 index 0000000000..d50af481af --- /dev/null +++ b/vendor/nim-lsquic @@ -0,0 +1 @@ +Subproject commit d50af481affa14aa57751439d3015a299c629e19