nwaku/waku/waku_enr/capabilities.nim

117 lines
3.4 KiB
Nim
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{.push raises: [].}
import
std/[options, bitops, sequtils, net, tables], results, eth/keys, libp2p/crypto/crypto
import ../common/enr, ../waku_core/codecs
const CapabilitiesEnrField* = "waku2"
type
## 8-bit flag field to indicate Waku node capabilities.
## Only the 4 LSBs are currently defined according
## to RFC31 (https://rfc.vac.dev/spec/31/).
CapabilitiesBitfield* = distinct uint8
## See: https://rfc.vac.dev/spec/31/#waku2-enr-key
## each enum numbers maps to a bit (where 0 is the LSB)
Capabilities* {.pure.} = enum
Relay = 0
Store = 1
Filter = 2
Lightpush = 3
Sync = 4
const capabilityToCodec = {
Capabilities.Relay: WakuRelayCodec,
Capabilities.Store: WakuStoreCodec,
Capabilities.Filter: WakuFilterSubscribeCodec,
Capabilities.Lightpush: WakuLightPushCodec,
Capabilities.Sync: WakuSyncCodec,
}.toTable
func init*(
T: type CapabilitiesBitfield, lightpush, filter, store, relay, sync: bool = false
): T =
## Creates an waku2 ENR flag bit field according to RFC 31 (https://rfc.vac.dev/spec/31/)
var bitfield: uint8
if relay:
bitfield.setBit(0)
if store:
bitfield.setBit(1)
if filter:
bitfield.setBit(2)
if lightpush:
bitfield.setBit(3)
if sync:
bitfield.setBit(4)
CapabilitiesBitfield(bitfield)
func init*(T: type CapabilitiesBitfield, caps: varargs[Capabilities]): T =
## Creates an waku2 ENR flag bit field according to RFC 31 (https://rfc.vac.dev/spec/31/)
var bitfield: uint8
for cap in caps:
bitfield.setBit(ord(cap))
CapabilitiesBitfield(bitfield)
converter toCapabilitiesBitfield*(field: uint8): CapabilitiesBitfield =
CapabilitiesBitfield(field)
proc supportsCapability*(bitfield: CapabilitiesBitfield, cap: Capabilities): bool =
testBit(bitfield.uint8, ord(cap))
func toCapabilities*(bitfield: CapabilitiesBitfield): seq[Capabilities] =
toSeq(Capabilities.low .. Capabilities.high).filterIt(
supportsCapability(bitfield, it)
)
# ENR builder extension
proc withWakuCapabilities*(builder: var EnrBuilder, caps: CapabilitiesBitfield) =
builder.addFieldPair(CapabilitiesEnrField, @[caps.uint8])
proc withWakuCapabilities*(builder: var EnrBuilder, caps: varargs[Capabilities]) =
withWakuCapabilities(builder, CapabilitiesBitfield.init(caps))
proc withWakuCapabilities*(builder: var EnrBuilder, caps: openArray[Capabilities]) =
withWakuCapabilities(builder, CapabilitiesBitfield.init(@caps))
# ENR record accessors (e.g., Record, TypedRecord, etc.)
func waku2*(record: TypedRecord): Option[CapabilitiesBitfield] =
let field = record.tryGet(CapabilitiesEnrField, seq[uint8])
if field.isNone():
return none(CapabilitiesBitfield)
if field.get().len != 1:
return none(CapabilitiesBitfield)
some(CapabilitiesBitfield(field.get()[0]))
proc supportsCapability*(r: Record, cap: Capabilities): bool =
let recordRes = r.toTyped()
if recordRes.isErr():
return false
let bitfieldOpt = recordRes.value.waku2
if bitfieldOpt.isNone():
return false
let bitfield = bitfieldOpt.get()
bitfield.supportsCapability(cap)
proc getCapabilities*(r: Record): seq[Capabilities] =
let recordRes = r.toTyped()
if recordRes.isErr():
return @[]
let bitfieldOpt = recordRes.value.waku2
if bitfieldOpt.isNone():
return @[]
let bitfield = bitfieldOpt.get()
bitfield.toCapabilities()
proc getCapabilitiesCodecs*(r: Record): seq[string] {.raises: [ValueError].} =
let capabilities = r.getCapabilities()
return capabilities.mapIt(capabilityToCodec[it])