Allow public address mapping (#767)

This commit is contained in:
Tanguy 2022-10-20 12:22:28 +02:00 committed by GitHub
parent 32233d36c8
commit 7b103e02f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 97 additions and 50 deletions

View File

@ -48,19 +48,19 @@ proc main() {.async.} =
swSrc = createCircuitRelaySwitch(clSrc) swSrc = createCircuitRelaySwitch(clSrc)
swDst = createCircuitRelaySwitch(clDst) swDst = createCircuitRelaySwitch(clDst)
# Create a relay address to swDst using swRel as the relay
addrs = MultiAddress.init($swRel.peerInfo.addrs[0] & "/p2p/" &
$swRel.peerInfo.peerId & "/p2p-circuit/p2p/" &
$swDst.peerInfo.peerId).get()
swDst.mount(proto) swDst.mount(proto)
await swRel.start() await swRel.start()
await swSrc.start() await swSrc.start()
await swDst.start() await swDst.start()
# Connect both Src and Dst to the relay, but not to each other. let
await swSrc.connect(swRel.peerInfo.peerId, swRel.peerInfo.addrs) # Create a relay address to swDst using swRel as the relay
addrs = MultiAddress.init($swRel.peerInfo.addrs[0] & "/p2p/" &
$swRel.peerInfo.peerId & "/p2p-circuit/p2p/" &
$swDst.peerInfo.peerId).get()
# Connect Dst to the relay
await swDst.connect(swRel.peerInfo.peerId, swRel.peerInfo.addrs) await swDst.connect(swRel.peerInfo.peerId, swRel.peerInfo.addrs)
# Dst reserve a slot on the relay. # Dst reserve a slot on the relay.

View File

@ -22,11 +22,17 @@ export peerid, multiaddress, crypto, routing_record, errors, results
## Our local peer info ## Our local peer info
type type
PeerInfoError* = LPError PeerInfoError* = object of LPError
AddressMapper* =
proc(listenAddrs: seq[MultiAddress]): Future[seq[MultiAddress]]
{.gcsafe, raises: [Defect].}
PeerInfo* {.public.} = ref object PeerInfo* {.public.} = ref object
peerId*: PeerId peerId*: PeerId
addrs*: seq[MultiAddress] listenAddrs*: seq[MultiAddress]
addrs: seq[MultiAddress]
addressMappers*: seq[AddressMapper]
protocols*: seq[string] protocols*: seq[string]
protoVersion*: string protoVersion*: string
agentVersion*: string agentVersion*: string
@ -37,6 +43,7 @@ type
func shortLog*(p: PeerInfo): auto = func shortLog*(p: PeerInfo): auto =
( (
peerId: $p.peerId, peerId: $p.peerId,
listenAddrs: mapIt(p.listenAddrs, $it),
addrs: mapIt(p.addrs, $it), addrs: mapIt(p.addrs, $it),
protocols: mapIt(p.protocols, $it), protocols: mapIt(p.protocols, $it),
protoVersion: p.protoVersion, protoVersion: p.protoVersion,
@ -44,7 +51,11 @@ func shortLog*(p: PeerInfo): auto =
) )
chronicles.formatIt(PeerInfo): shortLog(it) chronicles.formatIt(PeerInfo): shortLog(it)
proc update*(p: PeerInfo) = proc update*(p: PeerInfo) {.async.} =
p.addrs = p.listenAddrs
for mapper in p.addressMappers:
p.addrs = await mapper(p.addrs)
let sprRes = SignedPeerRecord.init( let sprRes = SignedPeerRecord.init(
p.privateKey, p.privateKey,
PeerRecord.init(p.peerId, p.addrs) PeerRecord.init(p.peerId, p.addrs)
@ -55,20 +66,25 @@ proc update*(p: PeerInfo) =
discard discard
#info "Can't update the signed peer record" #info "Can't update the signed peer record"
proc addrs*(p: PeerInfo): seq[MultiAddress] =
p.addrs
proc new*( proc new*(
p: typedesc[PeerInfo], p: typedesc[PeerInfo],
key: PrivateKey, key: PrivateKey,
addrs: openArray[MultiAddress] = [], listenAddrs: openArray[MultiAddress] = [],
protocols: openArray[string] = [], protocols: openArray[string] = [],
protoVersion: string = "", protoVersion: string = "",
agentVersion: string = ""): PeerInfo agentVersion: string = "",
{.raises: [Defect, PeerInfoError].} = addressMappers = newSeq[AddressMapper](),
): PeerInfo
{.raises: [Defect, LPError].} =
let pubkey = try: let pubkey = try:
key.getPublicKey().tryGet() key.getPublicKey().tryGet()
except CatchableError: except CatchableError:
raise newException(PeerInfoError, "invalid private key") raise newException(PeerInfoError, "invalid private key")
let peerId = PeerId.init(key).tryGet() let peerId = PeerId.init(key).tryGet()
let peerInfo = PeerInfo( let peerInfo = PeerInfo(
@ -77,10 +93,9 @@ proc new*(
privateKey: key, privateKey: key,
protoVersion: protoVersion, protoVersion: protoVersion,
agentVersion: agentVersion, agentVersion: agentVersion,
addrs: @addrs, listenAddrs: @listenAddrs,
protocols: @protocols, protocols: @protocols,
addressMappers: addressMappers
) )
peerInfo.update()
return peerInfo return peerInfo

View File

@ -299,11 +299,11 @@ proc start*(s: Switch) {.async, gcsafe, public.} =
trace "starting switch for peer", peerInfo = s.peerInfo trace "starting switch for peer", peerInfo = s.peerInfo
var startFuts: seq[Future[void]] var startFuts: seq[Future[void]]
for t in s.transports: for t in s.transports:
let addrs = s.peerInfo.addrs.filterIt( let addrs = s.peerInfo.listenAddrs.filterIt(
t.handles(it) t.handles(it)
) )
s.peerInfo.addrs.keepItIf( s.peerInfo.listenAddrs.keepItIf(
it notin addrs it notin addrs
) )
@ -320,9 +320,9 @@ proc start*(s: Switch) {.async, gcsafe, public.} =
for t in s.transports: # for each transport for t in s.transports: # for each transport
if t.addrs.len > 0 or t.running: if t.addrs.len > 0 or t.running:
s.acceptFuts.add(s.accept(t)) s.acceptFuts.add(s.accept(t))
s.peerInfo.addrs &= t.addrs s.peerInfo.listenAddrs &= t.addrs
s.peerInfo.update() await s.peerInfo.update()
await s.ms.start() await s.ms.start()

View File

@ -52,6 +52,9 @@ suite "Identify":
msListen = MultistreamSelect.new() msListen = MultistreamSelect.new()
msDial = MultistreamSelect.new() msDial = MultistreamSelect.new()
serverFut = transport1.start(ma)
await remotePeerInfo.update()
asyncTeardown: asyncTeardown:
await conn.close() await conn.close()
await acceptFut await acceptFut
@ -61,7 +64,6 @@ suite "Identify":
asyncTest "default agent version": asyncTest "default agent version":
msListen.addHandler(IdentifyCodec, identifyProto1) msListen.addHandler(IdentifyCodec, identifyProto1)
serverFut = transport1.start(ma)
proc acceptHandler(): Future[void] {.async, gcsafe.} = proc acceptHandler(): Future[void] {.async, gcsafe.} =
let c = await transport1.accept() let c = await transport1.accept()
await msListen.handle(c) await msListen.handle(c)
@ -84,8 +86,6 @@ suite "Identify":
remotePeerInfo.agentVersion = customAgentVersion remotePeerInfo.agentVersion = customAgentVersion
msListen.addHandler(IdentifyCodec, identifyProto1) msListen.addHandler(IdentifyCodec, identifyProto1)
serverFut = transport1.start(ma)
proc acceptHandler(): Future[void] {.async, gcsafe.} = proc acceptHandler(): Future[void] {.async, gcsafe.} =
let c = await transport1.accept() let c = await transport1.accept()
await msListen.handle(c) await msListen.handle(c)
@ -105,7 +105,6 @@ suite "Identify":
asyncTest "handle failed identify": asyncTest "handle failed identify":
msListen.addHandler(IdentifyCodec, identifyProto1) msListen.addHandler(IdentifyCodec, identifyProto1)
asyncSpawn transport1.start(ma)
proc acceptHandler() {.async.} = proc acceptHandler() {.async.} =
var conn: Connection var conn: Connection
@ -128,7 +127,6 @@ suite "Identify":
asyncTest "can send signed peer record": asyncTest "can send signed peer record":
msListen.addHandler(IdentifyCodec, identifyProto1) msListen.addHandler(IdentifyCodec, identifyProto1)
identifyProto1.sendSignedPeerRecord = true identifyProto1.sendSignedPeerRecord = true
serverFut = transport1.start(ma)
proc acceptHandler(): Future[void] {.async, gcsafe.} = proc acceptHandler(): Future[void] {.async, gcsafe.} =
let c = await transport1.accept() let c = await transport1.accept()
await msListen.handle(c) await msListen.handle(c)
@ -195,7 +193,8 @@ suite "Identify":
asyncTest "simple push identify": asyncTest "simple push identify":
switch2.peerInfo.protocols.add("/newprotocol/") switch2.peerInfo.protocols.add("/newprotocol/")
switch2.peerInfo.addrs.add(MultiAddress.init("/ip4/127.0.0.1/tcp/5555").tryGet()) switch2.peerInfo.listenAddrs.add(MultiAddress.init("/ip4/127.0.0.1/tcp/5555").tryGet())
await switch2.peerInfo.update()
check: check:
switch1.peerStore[AddressBook][switch2.peerInfo.peerId] != switch2.peerInfo.addrs switch1.peerStore[AddressBook][switch2.peerInfo.peerId] != switch2.peerInfo.addrs
@ -216,7 +215,8 @@ suite "Identify":
asyncTest "wrong peer id push identify": asyncTest "wrong peer id push identify":
switch2.peerInfo.protocols.add("/newprotocol/") switch2.peerInfo.protocols.add("/newprotocol/")
switch2.peerInfo.addrs.add(MultiAddress.init("/ip4/127.0.0.1/tcp/5555").tryGet()) switch2.peerInfo.listenAddrs.add(MultiAddress.init("/ip4/127.0.0.1/tcp/5555").tryGet())
await switch2.peerInfo.update()
check: check:
switch1.peerStore[AddressBook][switch2.peerInfo.peerId] != switch2.peerInfo.addrs switch1.peerStore[AddressBook][switch2.peerInfo.peerId] != switch2.peerInfo.addrs

View File

@ -60,8 +60,7 @@ method init(p: TestProto) {.gcsafe.} =
proc createSwitch(ma: MultiAddress; outgoing: bool, secio: bool = false): (Switch, PeerInfo) = proc createSwitch(ma: MultiAddress; outgoing: bool, secio: bool = false): (Switch, PeerInfo) =
var var
privateKey = PrivateKey.random(ECDSA, rng[]).get() privateKey = PrivateKey.random(ECDSA, rng[]).get()
peerInfo = PeerInfo.new(privateKey) peerInfo = PeerInfo.new(privateKey, @[ma])
peerInfo.addrs.add(ma)
proc createMplex(conn: Connection): Muxer = proc createMplex(conn: Connection): Muxer =
result = Mplex.new(conn) result = Mplex.new(conn)

View File

@ -18,22 +18,24 @@ suite "PeerInfo":
check peerId == peerInfo.peerId check peerId == peerInfo.peerId
check seckey.getPublicKey().get() == peerInfo.publicKey check seckey.getPublicKey().get() == peerInfo.publicKey
test "Signed peer record": test "Signed peer record":
const const
ExpectedDomain = $multiCodec("libp2p-peer-record") ExpectedDomain = $multiCodec("libp2p-peer-record")
ExpectedPayloadType = @[(byte) 0x03, (byte) 0x01] ExpectedPayloadType = @[(byte) 0x03, (byte) 0x01]
let let
seckey = PrivateKey.random(rng[]).tryGet() seckey = PrivateKey.random(rng[]).tryGet()
peerId = PeerId.init(seckey).get() peerId = PeerId.init(seckey).get()
multiAddresses = @[MultiAddress.init("/ip4/0.0.0.0/tcp/24").tryGet(), MultiAddress.init("/ip4/0.0.0.0/tcp/25").tryGet()] multiAddresses = @[MultiAddress.init("/ip4/0.0.0.0/tcp/24").tryGet(), MultiAddress.init("/ip4/0.0.0.0/tcp/25").tryGet()]
peerInfo = PeerInfo.new(seckey, multiAddresses) peerInfo = PeerInfo.new(seckey, multiAddresses)
waitFor(peerInfo.update())
let let
env = peerInfo.signedPeerRecord.envelope env = peerInfo.signedPeerRecord.envelope
rec = PeerRecord.decode(env.payload()).tryGet() rec = PeerRecord.decode(env.payload()).tryGet()
# Check envelope fields # Check envelope fields
check: check:
env.publicKey == peerInfo.publicKey env.publicKey == peerInfo.publicKey
@ -47,3 +49,17 @@ suite "PeerInfo":
rec.addresses.len == 2 rec.addresses.len == 2
rec.addresses[0].address == multiAddresses[0] rec.addresses[0].address == multiAddresses[0]
rec.addresses[1].address == multiAddresses[1] rec.addresses[1].address == multiAddresses[1]
test "Public address mapping":
let
seckey = PrivateKey.random(ECDSA, rng[]).get()
multiAddresses = @[MultiAddress.init("/ip4/0.0.0.0/tcp/24").tryGet(), MultiAddress.init("/ip4/0.0.0.0/tcp/25").tryGet()]
multiAddresses2 = @[MultiAddress.init("/ip4/8.8.8.8/tcp/33").tryGet()]
proc addressMapper(input: seq[MultiAddress]): Future[seq[MultiAddress]] {.async.} =
check input == multiAddresses
await sleepAsync(0.seconds)
return multiAddresses2
var peerInfo = PeerInfo.new(seckey, multiAddresses, addressMappers = @[addressMapper])
waitFor peerInfo.update()
check peerInfo.addrs == multiAddresses2

View File

@ -118,7 +118,6 @@ suite "Circuit Relay V2":
asyncTeardown: asyncTeardown:
checkTrackers() checkTrackers()
var var
addrs {.threadvar.}: MultiAddress
customProtoCodec {.threadvar.}: string customProtoCodec {.threadvar.}: string
proto {.threadvar.}: LPProtocol proto {.threadvar.}: LPProtocol
ttl {.threadvar.}: int ttl {.threadvar.}: int
@ -145,9 +144,6 @@ suite "Circuit Relay V2":
src = createSwitch(srcCl) src = createSwitch(srcCl)
dst = createSwitch(dstCl) dst = createSwitch(dstCl)
rel = newStandardSwitch() rel = newStandardSwitch()
addrs = MultiAddress.init($rel.peerInfo.addrs[0] & "/p2p/" &
$rel.peerInfo.peerId & "/p2p-circuit/p2p/" &
$dst.peerInfo.peerId).get()
asyncTest "Connection succeed": asyncTest "Connection succeed":
proto.handler = proc(conn: Connection, proto: string) {.async.} = proto.handler = proc(conn: Connection, proto: string) {.async.} =
@ -167,6 +163,10 @@ suite "Circuit Relay V2":
await src.start() await src.start()
await dst.start() await dst.start()
let addrs = MultiAddress.init($rel.peerInfo.addrs[0] & "/p2p/" &
$rel.peerInfo.peerId & "/p2p-circuit/p2p/" &
$dst.peerInfo.peerId).get()
await src.connect(rel.peerInfo.peerId, rel.peerInfo.addrs) await src.connect(rel.peerInfo.peerId, rel.peerInfo.addrs)
await dst.connect(rel.peerInfo.peerId, rel.peerInfo.addrs) await dst.connect(rel.peerInfo.peerId, rel.peerInfo.addrs)
@ -200,6 +200,10 @@ suite "Circuit Relay V2":
await src.start() await src.start()
await dst.start() await dst.start()
let addrs = MultiAddress.init($rel.peerInfo.addrs[0] & "/p2p/" &
$rel.peerInfo.peerId & "/p2p-circuit/p2p/" &
$dst.peerInfo.peerId).get()
await src.connect(rel.peerInfo.peerId, rel.peerInfo.addrs) await src.connect(rel.peerInfo.peerId, rel.peerInfo.addrs)
await dst.connect(rel.peerInfo.peerId, rel.peerInfo.addrs) await dst.connect(rel.peerInfo.peerId, rel.peerInfo.addrs)
@ -245,6 +249,10 @@ take to the ship.""")
await src.start() await src.start()
await dst.start() await dst.start()
let addrs = MultiAddress.init($rel.peerInfo.addrs[0] & "/p2p/" &
$rel.peerInfo.peerId & "/p2p-circuit/p2p/" &
$dst.peerInfo.peerId).get()
await src.connect(rel.peerInfo.peerId, rel.peerInfo.addrs) await src.connect(rel.peerInfo.peerId, rel.peerInfo.addrs)
await dst.connect(rel.peerInfo.peerId, rel.peerInfo.addrs) await dst.connect(rel.peerInfo.peerId, rel.peerInfo.addrs)
@ -277,6 +285,10 @@ take to the ship.""")
await src.start() await src.start()
await dst.start() await dst.start()
let addrs = MultiAddress.init($rel.peerInfo.addrs[0] & "/p2p/" &
$rel.peerInfo.peerId & "/p2p-circuit/p2p/" &
$dst.peerInfo.peerId).get()
await src.connect(rel.peerInfo.peerId, rel.peerInfo.addrs) await src.connect(rel.peerInfo.peerId, rel.peerInfo.addrs)
await dst.connect(rel.peerInfo.peerId, rel.peerInfo.addrs) await dst.connect(rel.peerInfo.peerId, rel.peerInfo.addrs)
@ -308,11 +320,6 @@ take to the ship.""")
rel2Cl = RelayClient.new(canHop = true) rel2Cl = RelayClient.new(canHop = true)
rel2 = createSwitch(rel2Cl) rel2 = createSwitch(rel2Cl)
rv2 = Relay.new() rv2 = Relay.new()
addrs = @[ MultiAddress.init($rel.peerInfo.addrs[0] & "/p2p/" &
$rel.peerInfo.peerId & "/p2p-circuit/p2p/" &
$rel2.peerInfo.peerId & "/p2p/" &
$rel2.peerInfo.peerId & "/p2p-circuit/p2p/" &
$dst.peerInfo.peerId).get() ]
rv2.setup(rel) rv2.setup(rel)
rel.mount(rv2) rel.mount(rv2)
dst.mount(proto) dst.mount(proto)
@ -321,6 +328,13 @@ take to the ship.""")
await src.start() await src.start()
await dst.start() await dst.start()
let
addrs = @[ MultiAddress.init($rel.peerInfo.addrs[0] & "/p2p/" &
$rel.peerInfo.peerId & "/p2p-circuit/p2p/" &
$rel2.peerInfo.peerId & "/p2p/" &
$rel2.peerInfo.peerId & "/p2p-circuit/p2p/" &
$dst.peerInfo.peerId).get() ]
await src.connect(rel.peerInfo.peerId, rel.peerInfo.addrs) await src.connect(rel.peerInfo.peerId, rel.peerInfo.addrs)
await rel2.connect(rel.peerInfo.peerId, rel.peerInfo.addrs) await rel2.connect(rel.peerInfo.peerId, rel.peerInfo.addrs)
await dst.connect(rel2.peerInfo.peerId, rel2.peerInfo.addrs) await dst.connect(rel2.peerInfo.peerId, rel2.peerInfo.addrs)
@ -367,6 +381,16 @@ take to the ship.""")
switchA = createSwitch(clientA) switchA = createSwitch(clientA)
switchB = createSwitch(clientB) switchB = createSwitch(clientB)
switchC = createSwitch(clientC) switchC = createSwitch(clientC)
switchA.mount(protoBCA)
switchB.mount(protoCAB)
switchC.mount(protoABC)
await switchA.start()
await switchB.start()
await switchC.start()
let
addrsABC = MultiAddress.init($switchB.peerInfo.addrs[0] & "/p2p/" & addrsABC = MultiAddress.init($switchB.peerInfo.addrs[0] & "/p2p/" &
$switchB.peerInfo.peerId & "/p2p-circuit/p2p/" & $switchB.peerInfo.peerId & "/p2p-circuit/p2p/" &
$switchC.peerInfo.peerId).get() $switchC.peerInfo.peerId).get()
@ -376,13 +400,6 @@ take to the ship.""")
addrsCAB = MultiAddress.init($switchA.peerInfo.addrs[0] & "/p2p/" & addrsCAB = MultiAddress.init($switchA.peerInfo.addrs[0] & "/p2p/" &
$switchA.peerInfo.peerId & "/p2p-circuit/p2p/" & $switchA.peerInfo.peerId & "/p2p-circuit/p2p/" &
$switchB.peerInfo.peerId).get() $switchB.peerInfo.peerId).get()
switchA.mount(protoBCA)
switchB.mount(protoCAB)
switchC.mount(protoABC)
await switchA.start()
await switchB.start()
await switchC.start()
await switchA.connect(switchB.peerInfo.peerId, switchB.peerInfo.addrs) await switchA.connect(switchB.peerInfo.peerId, switchB.peerInfo.addrs)
await switchB.connect(switchC.peerInfo.peerId, switchC.peerInfo.addrs) await switchB.connect(switchC.peerInfo.peerId, switchC.peerInfo.addrs)