Dht debug (#446)

* Support for building docker images with local modifications for the purpose of testing and debugging

* exposes peer information via debug/info

* api-names slightly kinder to json serializers

* Moves debug image-building

* fixes misalignment of debug peer info array

* Changes switchPeers source from KeyBook to AddressBook (filed ticket in libp2p, discussed with Tanguy)

* Limited success with dist-test peer discovery tests

* Removes unnecessary random-timer

* bumps dht repo. Adds peerId to formatNode

* Removes unused prints

* bumps libp2p-dht

* Exposes node address on debug api

* Adds traces

* review comments by me

* Hides debug/peers api behind compile flag

* Waiting for nim-libp2p-dht PR merge

* bumps libp2p-dht back to main after PRs were merged there.

* Cleanup
This commit is contained in:
Ben Bierens 2023-06-19 08:21:03 +02:00 committed by GitHub
parent 4f99d88c0a
commit db9d90b465
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 82 additions and 40 deletions

View File

@ -35,6 +35,9 @@ import ./stores
export DefaultCacheSizeMiB, net, DefaultQuotaBytes, DefaultBlockTtl, DefaultBlockMaintenanceInterval, DefaultNumberOfBlocksToMaintainPerInterval export DefaultCacheSizeMiB, net, DefaultQuotaBytes, DefaultBlockTtl, DefaultBlockMaintenanceInterval, DefaultNumberOfBlocksToMaintainPerInterval
const
codex_enable_api_debug_peers* {.booldefine.} = false
type type
StartUpCommand* {.pure.} = enum StartUpCommand* {.pure.} = enum
noCommand, noCommand,

View File

@ -35,7 +35,7 @@ logScope:
type type
Discovery* = ref object of RootObj Discovery* = ref object of RootObj
protocol: discv5.Protocol # dht protocol protocol*: discv5.Protocol # dht protocol
key: PrivateKey # private key key: PrivateKey # private key
peerId: PeerId # the peer id of the local node peerId: PeerId # the peer id of the local node
announceAddrs: seq[MultiAddress] # addresses announced as part of the provider records announceAddrs: seq[MultiAddress] # addresses announced as part of the provider records
@ -58,13 +58,16 @@ proc toNodeId*(host: ca.Address): NodeId =
proc findPeer*( proc findPeer*(
d: Discovery, d: Discovery,
peerId: PeerId): Future[?PeerRecord] {.async.} = peerId: PeerId): Future[?PeerRecord] {.async.} =
trace "protocol.resolve..."
let let
node = await d.protocol.resolve(toNodeId(peerId)) node = await d.protocol.resolve(toNodeId(peerId))
return return
if node.isSome(): if node.isSome():
trace "protocol.resolve some data"
node.get().record.data.some node.get().record.data.some
else: else:
trace "protocol.resolve none"
PeerRecord.none PeerRecord.none
method find*( method find*(
@ -127,16 +130,10 @@ method provide*(d: Discovery, host: ca.Address) {.async, base.} =
trace "Provided to nodes", nodes = nodes.len trace "Provided to nodes", nodes = nodes.len
method removeProvider*(d: Discovery, peerId: PeerId): Future[void] {.base.} = method removeProvider*(d: Discovery, peerId: PeerId): Future[void] {.base.} =
## Remove provider from providers table
##
trace "Removing provider", peerId trace "Removing provider", peerId
d.protocol.removeProvidersLocal(peerId) d.protocol.removeProvidersLocal(peerId)
proc updateAnnounceRecord*(d: Discovery, addrs: openArray[MultiAddress]) = proc updateAnnounceRecord*(d: Discovery, addrs: openArray[MultiAddress]) =
## Update providers record
##
d.announceAddrs = @addrs d.announceAddrs = @addrs
trace "Updating announce record", addrs = d.announceAddrs trace "Updating announce record", addrs = d.announceAddrs
@ -149,9 +146,6 @@ proc updateAnnounceRecord*(d: Discovery, addrs: openArray[MultiAddress]) =
.expect("Should update SPR") .expect("Should update SPR")
proc updateDhtRecord*(d: Discovery, ip: ValidIpAddress, port: Port) = proc updateDhtRecord*(d: Discovery, ip: ValidIpAddress, port: Port) =
## Update providers record
##
trace "Updating Dht record", ip, port = $port trace "Updating Dht record", ip, port = $port
d.dhtRecord = SignedPeerRecord.init( d.dhtRecord = SignedPeerRecord.init(
d.key, PeerRecord.init(d.peerId, @[ d.key, PeerRecord.init(d.peerId, @[
@ -160,6 +154,10 @@ proc updateDhtRecord*(d: Discovery, ip: ValidIpAddress, port: Port) =
IpTransportProtocol.udpProtocol, IpTransportProtocol.udpProtocol,
port)])).expect("Should construct signed record").some port)])).expect("Should construct signed record").some
if not d.protocol.isNil:
d.protocol.updateRecord(d.dhtRecord)
.expect("Should update SPR")
proc start*(d: Discovery) {.async.} = proc start*(d: Discovery) {.async.} =
d.protocol.open() d.protocol.open()
await d.protocol.start() await d.protocol.start()

View File

@ -24,8 +24,11 @@ import pkg/stew/base10
import pkg/stew/byteutils import pkg/stew/byteutils
import pkg/confutils import pkg/confutils
import pkg/libp2p
import pkg/libp2p/routing_record import pkg/libp2p/routing_record
import pkg/libp2pdht/discv5/spr as spr import pkg/libp2pdht/discv5/spr as spr
import pkg/libp2pdht/discv5/routing_table as rt
import pkg/libp2pdht/discv5/node as dn
import ../node import ../node
import ../blocktype import ../blocktype
@ -45,6 +48,47 @@ proc validate(
{.gcsafe, raises: [Defect].} = {.gcsafe, raises: [Defect].} =
0 0
proc formatAddress(address: Option[dn.Address]): string =
if address.isSome():
return $address.get()
return "<none>"
proc formatNode(node: dn.Node): JsonNode =
let jobj = %*{
"nodeId": $node.id,
"peerId": $node.record.data.peerId,
"record": $node.record,
"address": formatAddress(node.address),
"seen": $node.seen
}
return jobj
proc formatTable(routingTable: rt.RoutingTable): JsonNode =
let jarray = newJArray()
for bucket in routingTable.buckets:
for node in bucket.nodes:
jarray.add(formatNode(node))
let jobj = %*{
"localNode": formatNode(routingTable.localNode),
"nodes": jarray
}
return jobj
proc formatPeerRecord(peerRecord: PeerRecord): JsonNode =
let jarray = newJArray()
for maddr in peerRecord.addresses:
jarray.add(%*{
"address": $maddr.address
})
let jobj = %*{
"peerId": $peerRecord.peerId,
"seqNo": $peerRecord.seqNo,
"addresses": jarray
}
return jobj
proc initRestApi*(node: CodexNodeRef, conf: CodexConf): RestRouter = proc initRestApi*(node: CodexNodeRef, conf: CodexConf): RestRouter =
var router = RestRouter.init(validate) var router = RestRouter.init(validate)
router.api( router.api(
@ -244,6 +288,7 @@ proc initRestApi*(node: CodexNodeRef, conf: CodexConf): RestRouter =
node.discovery.dhtRecord.get.toURI node.discovery.dhtRecord.get.toURI
else: else:
"", "",
"table": formatTable(node.discovery.protocol.routingTable),
"codex": { "codex": {
"version": $codexVersion, "version": $codexVersion,
"revision": $codexRevision "revision": $codexRevision
@ -252,6 +297,22 @@ proc initRestApi*(node: CodexNodeRef, conf: CodexConf): RestRouter =
return RestApiResponse.response($json, contentType="application/json") return RestApiResponse.response($json, contentType="application/json")
when codex_enable_api_debug_peers:
router.api(
MethodGet,
"/api/codex/v1/debug/peer/{peerId}") do (peerId: PeerId) -> RestApiResponse:
trace "debug/peer start"
without peerRecord =? (await node.findPeer(peerId.get())):
trace "debug/peer peer not found!"
return RestApiResponse.error(
Http400,
"Unable to find Peer!")
let json = formatPeerRecord(peerRecord)
trace "debug/peer returning peer record"
return RestApiResponse.response($json)
router.api( router.api(
MethodGet, MethodGet,
"/api/codex/v1/sales/availability") do () -> RestApiResponse: "/api/codex/v1/sales/availability") do () -> RestApiResponse:
@ -313,5 +374,4 @@ proc initRestApi*(node: CodexNodeRef, conf: CodexConf): RestRouter =
return RestApiResponse.response($json, contentType="application/json") return RestApiResponse.response($json, contentType="application/json")
return router return router

View File

@ -3,8 +3,8 @@ WORKDIR /src
RUN apk update && apk add git cmake curl make git bash linux-headers RUN apk update && apk add git cmake curl make git bash linux-headers
COPY . . COPY . .
RUN make clean RUN make clean
RUN make update RUN make -j4 update
RUN make NIM_PARAMS="-d:disableMarchNative" RUN make -j4 NIM_PARAMS="-d:disableMarchNative -d:codex_enable_api_debug_peers=true"
FROM alpine:3.17.2 FROM alpine:3.17.2
WORKDIR /root/ WORKDIR /root/

View File

@ -1,6 +0,0 @@
groups:
- name: DemoAlerts
rules:
- alert: InstanceDown
expr: up{job="services"} < 1
for: 5m

View File

@ -1,15 +0,0 @@
global:
scrape_interval: 30s
scrape_timeout: 10s
rule_files:
- alert.yml
scrape_configs:
- job_name: services
metrics_path: /metrics
static_configs:
- targets:
- 'prometheus:9090'
- 'codex-node1:9090'
- 'codex-node2:9090'

View File

@ -2,6 +2,10 @@ echo "Starting Codex..."
args="" args=""
## Using local ip as NAT
nat_addr=$(ifconfig eth0 | awk '/inet addr/ {gsub("addr:", "", $2); print $2}')
echo "Local IP: $nat_addr"
# Required arguments # Required arguments
if [ -n "$LISTEN_ADDRS" ]; then if [ -n "$LISTEN_ADDRS" ]; then
echo "Listen address: $LISTEN_ADDRS" echo "Listen address: $LISTEN_ADDRS"
@ -40,10 +44,8 @@ if [ -n "$METRICS_ADDR" ] && [ -n "$METRICS_PORT" ]; then
fi fi
# NAT # NAT
if [ -n "$NAT_IP" ]; then echo "NAT: $nat_addr"
echo "NAT: $NAT_IP" args="$args --nat=$nat_addr"
args="$args --nat=$NAT_IP"
fi
# Discovery IP # Discovery IP
if [ -n "$DISC_IP" ]; then if [ -n "$DISC_IP" ]; then
@ -108,7 +110,7 @@ fi
# Ethereum persistence # Ethereum persistence
if [ -n "$ETH_PROVIDER" ] && [ -n "$ETH_ACCOUNT" ] && [ -n "$ETH_MARKETPLACE_ADDRESS" ]; then if [ -n "$ETH_PROVIDER" ] && [ -n "$ETH_ACCOUNT" ] && [ -n "$ETH_MARKETPLACE_ADDRESS" ]; then
echo "Persistence enabled" echo "Persistence enabled"
args="$args --persistence=true" args="$args --persistence"
args="$args --eth-provider=$ETH_PROVIDER" args="$args --eth-provider=$ETH_PROVIDER"
args="$args --eth-account=$ETH_ACCOUNT" args="$args --eth-account=$ETH_ACCOUNT"
# args="$args --validator" # args="$args --validator"

@ -1 +1 @@
Subproject commit 4375b9229815c332a3b1a9d0091d5cf5a74adb2e Subproject commit bd517f0e8da38a1b5da15f7deb2d5c652ca389f1