mirror of https://github.com/vacp2p/nim-libp2p.git
allow to omit peerId and seqno (#372)
* allow to omit peerId and seqno * small refactor * wip * fix message encoding * improve rpc signature logic * remove peerid from verify * trace fixes * fix message test * fix gossip 1.0 tests
This commit is contained in:
parent
abd234601b
commit
ec322124ac
|
@ -72,10 +72,19 @@ method rpcHandler*(f: FloodSub,
|
||||||
trace "Dropping already-seen message", msgId, peer
|
trace "Dropping already-seen message", msgId, peer
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if f.verifySignature and not msg.verify(peer.peerId):
|
if (msg.signature.len > 0 or f.verifySignature) and not msg.verify():
|
||||||
|
# always validate if signature is present or required
|
||||||
debug "Dropping message due to failed signature verification", msgId, peer
|
debug "Dropping message due to failed signature verification", msgId, peer
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if msg.seqno.len > 0 and msg.seqno.len != 8:
|
||||||
|
# if we have seqno should be 8 bytes long
|
||||||
|
debug "Dropping message due to invalid seqno length", msgId, peer
|
||||||
|
continue
|
||||||
|
|
||||||
|
# g.anonymize needs no evaluation when receiving messages
|
||||||
|
# as we have a "lax" policy and allow signed messages
|
||||||
|
|
||||||
if not (await f.validate(msg)):
|
if not (await f.validate(msg)):
|
||||||
trace "Dropping message due to failed validation", msgId, peer
|
trace "Dropping message due to failed validation", msgId, peer
|
||||||
continue
|
continue
|
||||||
|
@ -129,7 +138,11 @@ method publish*(f: FloodSub,
|
||||||
|
|
||||||
inc f.msgSeqno
|
inc f.msgSeqno
|
||||||
let
|
let
|
||||||
msg = Message.init(f.peerInfo, data, topic, f.msgSeqno, f.sign)
|
msg =
|
||||||
|
if f.anonymize:
|
||||||
|
Message.init(none(PeerInfo), data, topic, none(uint64), false)
|
||||||
|
else:
|
||||||
|
Message.init(some(f.peerInfo), data, topic, some(f.msgSeqno), f.sign)
|
||||||
msgId = f.msgIdProvider(msg)
|
msgId = f.msgIdProvider(msg)
|
||||||
|
|
||||||
trace "Created new message",
|
trace "Created new message",
|
||||||
|
|
|
@ -1046,11 +1046,21 @@ method rpcHandler*(g: GossipSub,
|
||||||
|
|
||||||
g.mcache.put(msgId, msg)
|
g.mcache.put(msgId, msg)
|
||||||
|
|
||||||
if g.verifySignature and not msg.verify(peer.peerId):
|
if (msg.signature.len > 0 or g.verifySignature) and not msg.verify():
|
||||||
|
# always validate if signature is present or required
|
||||||
debug "Dropping message due to failed signature verification", msgId, peer
|
debug "Dropping message due to failed signature verification", msgId, peer
|
||||||
g.punishPeer(peer, msg)
|
g.punishPeer(peer, msg)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if msg.seqno.len > 0 and msg.seqno.len != 8:
|
||||||
|
# if we have seqno should be 8 bytes long
|
||||||
|
debug "Dropping message due to invalid seqno length", msgId, peer
|
||||||
|
g.punishPeer(peer, msg)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# g.anonymize needs no evaluation when receiving messages
|
||||||
|
# as we have a "lax" policy and allow signed messages
|
||||||
|
|
||||||
if not (await g.validate(msg)):
|
if not (await g.validate(msg)):
|
||||||
debug "Dropping message due to failed validation", msgId, peer
|
debug "Dropping message due to failed validation", msgId, peer
|
||||||
g.punishPeer(peer, msg)
|
g.punishPeer(peer, msg)
|
||||||
|
@ -1197,7 +1207,11 @@ method publish*(g: GossipSub,
|
||||||
|
|
||||||
inc g.msgSeqno
|
inc g.msgSeqno
|
||||||
let
|
let
|
||||||
msg = Message.init(g.peerInfo, data, topic, g.msgSeqno, g.sign)
|
msg =
|
||||||
|
if g.anonymize:
|
||||||
|
Message.init(none(PeerInfo), data, topic, none(uint64), false)
|
||||||
|
else:
|
||||||
|
Message.init(some(g.peerInfo), data, topic, some(g.msgSeqno), g.sign)
|
||||||
msgId = g.msgIdProvider(msg)
|
msgId = g.msgIdProvider(msg)
|
||||||
|
|
||||||
logScope: msgId
|
logScope: msgId
|
||||||
|
|
|
@ -451,10 +451,19 @@ method rpcHandler*(g: GossipSub,
|
||||||
|
|
||||||
g.mcache.put(msgId, msg)
|
g.mcache.put(msgId, msg)
|
||||||
|
|
||||||
if g.verifySignature and not msg.verify(peer.peerId):
|
if (msg.signature.len > 0 or g.verifySignature) and not msg.verify():
|
||||||
|
# always validate if signature is present or required
|
||||||
debug "Dropping message due to failed signature verification", msgId, peer
|
debug "Dropping message due to failed signature verification", msgId, peer
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if msg.seqno.len > 0 and msg.seqno.len != 8:
|
||||||
|
# if we have seqno should be 8 bytes long
|
||||||
|
debug "Dropping message due to invalid seqno length", msgId, peer
|
||||||
|
continue
|
||||||
|
|
||||||
|
# g.anonymize needs no evaluation when receiving messages
|
||||||
|
# as we have a "lax" policy and allow signed messages
|
||||||
|
|
||||||
if not (await g.validate(msg)):
|
if not (await g.validate(msg)):
|
||||||
trace "Dropping message due to failed validation", msgId, peer
|
trace "Dropping message due to failed validation", msgId, peer
|
||||||
continue
|
continue
|
||||||
|
@ -556,7 +565,11 @@ method publish*(g: GossipSub,
|
||||||
|
|
||||||
inc g.msgSeqno
|
inc g.msgSeqno
|
||||||
let
|
let
|
||||||
msg = Message.init(g.peerInfo, data, topic, g.msgSeqno, g.sign)
|
msg =
|
||||||
|
if g.anonymize:
|
||||||
|
Message.init(none(PeerInfo), data, topic, none(uint64), false)
|
||||||
|
else:
|
||||||
|
Message.init(some(g.peerInfo), data, topic, some(g.msgSeqno), g.sign)
|
||||||
msgId = g.msgIdProvider(msg)
|
msgId = g.msgIdProvider(msg)
|
||||||
|
|
||||||
logScope: msgId
|
logScope: msgId
|
||||||
|
|
|
@ -67,6 +67,7 @@ type
|
||||||
observers: ref seq[PubSubObserver] # ref as in smart_ptr
|
observers: ref seq[PubSubObserver] # ref as in smart_ptr
|
||||||
msgIdProvider*: MsgIdProvider # Turn message into message id (not nil)
|
msgIdProvider*: MsgIdProvider # Turn message into message id (not nil)
|
||||||
msgSeqno*: uint64
|
msgSeqno*: uint64
|
||||||
|
anonymize*: bool # if we omit fromPeer and seqno from RPC messages we send
|
||||||
|
|
||||||
method unsubscribePeer*(p: PubSub, peerId: PeerID) {.base.} =
|
method unsubscribePeer*(p: PubSub, peerId: PeerID) {.base.} =
|
||||||
## handle peer disconnects
|
## handle peer disconnects
|
||||||
|
@ -329,6 +330,7 @@ proc init*[PubParams: object | bool](
|
||||||
P: typedesc[PubSub],
|
P: typedesc[PubSub],
|
||||||
switch: Switch,
|
switch: Switch,
|
||||||
triggerSelf: bool = false,
|
triggerSelf: bool = false,
|
||||||
|
anonymize: bool = false,
|
||||||
verifySignature: bool = true,
|
verifySignature: bool = true,
|
||||||
sign: bool = true,
|
sign: bool = true,
|
||||||
msgIdProvider: MsgIdProvider = defaultMsgIdProvider,
|
msgIdProvider: MsgIdProvider = defaultMsgIdProvider,
|
||||||
|
@ -338,6 +340,7 @@ proc init*[PubParams: object | bool](
|
||||||
P(switch: switch,
|
P(switch: switch,
|
||||||
peerInfo: switch.peerInfo,
|
peerInfo: switch.peerInfo,
|
||||||
triggerSelf: triggerSelf,
|
triggerSelf: triggerSelf,
|
||||||
|
anonymize: anonymize,
|
||||||
verifySignature: verifySignature,
|
verifySignature: verifySignature,
|
||||||
sign: sign,
|
sign: sign,
|
||||||
peers: initTable[PeerID, PubSubPeer](),
|
peers: initTable[PeerID, PubSubPeer](),
|
||||||
|
@ -347,6 +350,7 @@ proc init*[PubParams: object | bool](
|
||||||
P(switch: switch,
|
P(switch: switch,
|
||||||
peerInfo: switch.peerInfo,
|
peerInfo: switch.peerInfo,
|
||||||
triggerSelf: triggerSelf,
|
triggerSelf: triggerSelf,
|
||||||
|
anonymize: anonymize,
|
||||||
verifySignature: verifySignature,
|
verifySignature: verifySignature,
|
||||||
sign: sign,
|
sign: sign,
|
||||||
peers: initTable[PeerID, PubSubPeer](),
|
peers: initTable[PeerID, PubSubPeer](),
|
||||||
|
|
|
@ -33,7 +33,7 @@ func defaultMsgIdProvider*(m: Message): string =
|
||||||
proc sign*(msg: Message, privateKey: PrivateKey): CryptoResult[seq[byte]] =
|
proc sign*(msg: Message, privateKey: PrivateKey): CryptoResult[seq[byte]] =
|
||||||
ok((? privateKey.sign(PubSubPrefix & encodeMessage(msg))).getBytes())
|
ok((? privateKey.sign(PubSubPrefix & encodeMessage(msg))).getBytes())
|
||||||
|
|
||||||
proc verify*(m: Message, p: PeerID): bool =
|
proc verify*(m: Message): bool =
|
||||||
if m.signature.len > 0 and m.key.len > 0:
|
if m.signature.len > 0 and m.key.len > 0:
|
||||||
var msg = m
|
var msg = m
|
||||||
msg.signature = @[]
|
msg.signature = @[]
|
||||||
|
@ -52,20 +52,26 @@ proc verify*(m: Message, p: PeerID): bool =
|
||||||
|
|
||||||
proc init*(
|
proc init*(
|
||||||
T: type Message,
|
T: type Message,
|
||||||
peer: PeerInfo,
|
peer: Option[PeerInfo],
|
||||||
data: seq[byte],
|
data: seq[byte],
|
||||||
topic: string,
|
topic: string,
|
||||||
seqno: uint64,
|
seqno: Option[uint64],
|
||||||
sign: bool = true): Message {.gcsafe, raises: [CatchableError, Defect].} =
|
sign: bool = true): Message {.gcsafe, raises: [CatchableError, Defect].} =
|
||||||
result = Message(
|
var msg = Message(data: data, topicIDs: @[topic])
|
||||||
fromPeer: peer.peerId,
|
|
||||||
data: data,
|
|
||||||
seqno: @(seqno.toBytesBE), # unefficient, fine for now
|
|
||||||
topicIDs: @[topic])
|
|
||||||
|
|
||||||
if sign:
|
# order matters, we want to include seqno in the signature
|
||||||
if peer.keyType != KeyType.HasPrivate:
|
if seqno.isSome:
|
||||||
raise (ref CatchableError)(msg: "Cannot sign message without private key")
|
msg.seqno = @(seqno.get().toBytesBE())
|
||||||
|
|
||||||
result.signature = sign(result, peer.privateKey).tryGet()
|
if peer.isSome:
|
||||||
result.key = peer.privateKey.getKey().tryGet().getBytes().tryGet()
|
let peer = peer.get()
|
||||||
|
msg.fromPeer = peer.peerId
|
||||||
|
if sign:
|
||||||
|
if peer.keyType != KeyType.HasPrivate:
|
||||||
|
raise (ref CatchableError)(msg: "Cannot sign message without private key")
|
||||||
|
msg.signature = sign(msg, peer.privateKey).tryGet()
|
||||||
|
msg.key = peer.privateKey.getKey().tryGet().getBytes().tryGet()
|
||||||
|
elif sign:
|
||||||
|
raise (ref CatchableError)(msg: "Cannot sign message without peer info")
|
||||||
|
|
||||||
|
msg
|
||||||
|
|
|
@ -2,6 +2,7 @@ include ../../libp2p/protocols/pubsub/gossipsub
|
||||||
|
|
||||||
{.used.}
|
{.used.}
|
||||||
|
|
||||||
|
import options
|
||||||
import unittest, bearssl
|
import unittest, bearssl
|
||||||
import stew/byteutils
|
import stew/byteutils
|
||||||
import ../../libp2p/standard_setup
|
import ../../libp2p/standard_setup
|
||||||
|
@ -267,7 +268,7 @@ suite "GossipSub internal":
|
||||||
let peerInfo = randomPeerInfo()
|
let peerInfo = randomPeerInfo()
|
||||||
conn.peerInfo = peerInfo
|
conn.peerInfo = peerInfo
|
||||||
inc seqno
|
inc seqno
|
||||||
let msg = Message.init(peerInfo, ("HELLO" & $i).toBytes(), topic, seqno, false)
|
let msg = Message.init(some(peerInfo), ("HELLO" & $i).toBytes(), topic, some(seqno), false)
|
||||||
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
|
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
|
||||||
|
|
||||||
check gossipSub.fanout[topic].len == 15
|
check gossipSub.fanout[topic].len == 15
|
||||||
|
@ -321,7 +322,7 @@ suite "GossipSub internal":
|
||||||
let peerInfo = randomPeerInfo()
|
let peerInfo = randomPeerInfo()
|
||||||
conn.peerInfo = peerInfo
|
conn.peerInfo = peerInfo
|
||||||
inc seqno
|
inc seqno
|
||||||
let msg = Message.init(peerInfo, ("HELLO" & $i).toBytes(), topic, seqno, false)
|
let msg = Message.init(some(peerInfo), ("HELLO" & $i).toBytes(), topic, some(seqno), false)
|
||||||
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
|
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
|
||||||
|
|
||||||
let peers = gossipSub.getGossipPeers()
|
let peers = gossipSub.getGossipPeers()
|
||||||
|
@ -369,7 +370,7 @@ suite "GossipSub internal":
|
||||||
let peerInfo = randomPeerInfo()
|
let peerInfo = randomPeerInfo()
|
||||||
conn.peerInfo = peerInfo
|
conn.peerInfo = peerInfo
|
||||||
inc seqno
|
inc seqno
|
||||||
let msg = Message.init(peerInfo, ("HELLO" & $i).toBytes(), topic, seqno, false)
|
let msg = Message.init(some(peerInfo), ("HELLO" & $i).toBytes(), topic, some(seqno), false)
|
||||||
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
|
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
|
||||||
|
|
||||||
let peers = gossipSub.getGossipPeers()
|
let peers = gossipSub.getGossipPeers()
|
||||||
|
@ -417,7 +418,7 @@ suite "GossipSub internal":
|
||||||
let peerInfo = randomPeerInfo()
|
let peerInfo = randomPeerInfo()
|
||||||
conn.peerInfo = peerInfo
|
conn.peerInfo = peerInfo
|
||||||
inc seqno
|
inc seqno
|
||||||
let msg = Message.init(peerInfo, ("bar" & $i).toBytes(), topic, seqno, false)
|
let msg = Message.init(some(peerInfo), ("bar" & $i).toBytes(), topic, some(seqno), false)
|
||||||
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
|
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
|
||||||
|
|
||||||
let peers = gossipSub.getGossipPeers()
|
let peers = gossipSub.getGossipPeers()
|
||||||
|
|
|
@ -2,6 +2,7 @@ include ../../libp2p/protocols/pubsub/gossipsub10
|
||||||
|
|
||||||
{.used.}
|
{.used.}
|
||||||
|
|
||||||
|
import options
|
||||||
import unittest, bearssl
|
import unittest, bearssl
|
||||||
import stew/byteutils
|
import stew/byteutils
|
||||||
import ../../libp2p/standard_setup
|
import ../../libp2p/standard_setup
|
||||||
|
@ -244,7 +245,7 @@ suite "GossipSub internal":
|
||||||
let peerInfo = randomPeerInfo()
|
let peerInfo = randomPeerInfo()
|
||||||
conn.peerInfo = peerInfo
|
conn.peerInfo = peerInfo
|
||||||
inc seqno
|
inc seqno
|
||||||
let msg = Message.init(peerInfo, ("HELLO" & $i).toBytes(), topic, seqno, false)
|
let msg = Message.init(some(peerInfo), ("HELLO" & $i).toBytes(), topic, some(seqno), false)
|
||||||
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
|
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
|
||||||
|
|
||||||
check gossipSub.fanout[topic].len == 15
|
check gossipSub.fanout[topic].len == 15
|
||||||
|
@ -296,7 +297,7 @@ suite "GossipSub internal":
|
||||||
let peerInfo = randomPeerInfo()
|
let peerInfo = randomPeerInfo()
|
||||||
conn.peerInfo = peerInfo
|
conn.peerInfo = peerInfo
|
||||||
inc seqno
|
inc seqno
|
||||||
let msg = Message.init(peerInfo, ("HELLO" & $i).toBytes(), topic, seqno, false)
|
let msg = Message.init(some(peerInfo), ("HELLO" & $i).toBytes(), topic, some(seqno), false)
|
||||||
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
|
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
|
||||||
|
|
||||||
let peers = gossipSub.getGossipPeers()
|
let peers = gossipSub.getGossipPeers()
|
||||||
|
@ -341,7 +342,7 @@ suite "GossipSub internal":
|
||||||
let peerInfo = randomPeerInfo()
|
let peerInfo = randomPeerInfo()
|
||||||
conn.peerInfo = peerInfo
|
conn.peerInfo = peerInfo
|
||||||
inc seqno
|
inc seqno
|
||||||
let msg = Message.init(peerInfo, ("HELLO" & $i).toBytes(), topic, seqno, false)
|
let msg = Message.init(some(peerInfo), ("HELLO" & $i).toBytes(), topic, some(seqno), false)
|
||||||
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
|
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
|
||||||
|
|
||||||
let peers = gossipSub.getGossipPeers()
|
let peers = gossipSub.getGossipPeers()
|
||||||
|
@ -386,7 +387,7 @@ suite "GossipSub internal":
|
||||||
let peerInfo = randomPeerInfo()
|
let peerInfo = randomPeerInfo()
|
||||||
conn.peerInfo = peerInfo
|
conn.peerInfo = peerInfo
|
||||||
inc seqno
|
inc seqno
|
||||||
let msg = Message.init(peerInfo, ("bar" & $i).toBytes(), topic, seqno, false)
|
let msg = Message.init(some(peerInfo), ("bar" & $i).toBytes(), topic, some(seqno), false)
|
||||||
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
|
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
|
||||||
|
|
||||||
let peers = gossipSub.getGossipPeers()
|
let peers = gossipSub.getGossipPeers()
|
||||||
|
|
|
@ -2,6 +2,7 @@ import unittest
|
||||||
|
|
||||||
{.used.}
|
{.used.}
|
||||||
|
|
||||||
|
import options
|
||||||
import ../../libp2p/[peerid, peerinfo,
|
import ../../libp2p/[peerid, peerinfo,
|
||||||
crypto/crypto,
|
crypto/crypto,
|
||||||
protocols/pubsub/rpc/message,
|
protocols/pubsub/rpc/message,
|
||||||
|
@ -14,6 +15,6 @@ suite "Message":
|
||||||
var seqno = 11'u64
|
var seqno = 11'u64
|
||||||
let
|
let
|
||||||
peer = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get())
|
peer = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get())
|
||||||
msg = Message.init(peer, @[], "topic", seqno, sign = true)
|
msg = Message.init(some(peer), @[], "topic", some(seqno), sign = true)
|
||||||
|
|
||||||
check verify(msg, peer.peerId)
|
check verify(msg)
|
||||||
|
|
Loading…
Reference in New Issue