mirror of
https://github.com/logos-messaging/go-libp2p-pubsub.git
synced 2026-01-08 15:53:07 +00:00
Send IDONTWANT before first publish (#612)
See #610 We previously send IDONTWANT only when forwarding. This has us send IDONTWANT on our initial publish as well. Helps in the case that one or more peers may also publish the same thing at around the same time (see #610 for a longer explanation) and prevents "boomerang" duplicates where a peer sends you back the message you sent before you get a chance to send it to them. This also serves as a hint to a peer that you are about to send them a certain message.
This commit is contained in:
parent
0c5ee7bbfe
commit
9e5145fb29
@ -71,7 +71,7 @@ func (fs *FloodSubRouter) AcceptFrom(peer.ID) AcceptStatus {
|
|||||||
return AcceptAll
|
return AcceptAll
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FloodSubRouter) PreValidation(from peer.ID, msgs []*Message) {}
|
func (fs *FloodSubRouter) Preprocess(from peer.ID, msgs []*Message) {}
|
||||||
|
|
||||||
func (fs *FloodSubRouter) HandleRPC(rpc *RPC) {}
|
func (fs *FloodSubRouter) HandleRPC(rpc *RPC) {}
|
||||||
|
|
||||||
|
|||||||
@ -707,10 +707,10 @@ func (gs *GossipSubRouter) AcceptFrom(p peer.ID) AcceptStatus {
|
|||||||
return gs.gate.AcceptFrom(p)
|
return gs.gate.AcceptFrom(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PreValidation sends the IDONTWANT control messages to all the mesh
|
// Preprocess sends the IDONTWANT control messages to all the mesh
|
||||||
// peers. They need to be sent right before the validation because they
|
// peers. They need to be sent right before the validation because they
|
||||||
// should be seen by the peers as soon as possible.
|
// should be seen by the peers as soon as possible.
|
||||||
func (gs *GossipSubRouter) PreValidation(from peer.ID, msgs []*Message) {
|
func (gs *GossipSubRouter) Preprocess(from peer.ID, msgs []*Message) {
|
||||||
tmids := make(map[string][]string)
|
tmids := make(map[string][]string)
|
||||||
for _, msg := range msgs {
|
for _, msg := range msgs {
|
||||||
if len(msg.GetData()) < gs.params.IDontWantMessageThreshold {
|
if len(msg.GetData()) < gs.params.IDontWantMessageThreshold {
|
||||||
|
|||||||
@ -2847,7 +2847,7 @@ var _ RawTracer = &mockRawTracer{}
|
|||||||
func TestGossipsubNoIDONTWANTToMessageSender(t *testing.T) {
|
func TestGossipsubNoIDONTWANTToMessageSender(t *testing.T) {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
hosts := getDefaultHosts(t, 3)
|
hosts := getDefaultHosts(t, 2)
|
||||||
denseConnect(t, hosts)
|
denseConnect(t, hosts)
|
||||||
|
|
||||||
psubs := make([]*PubSub, 2)
|
psubs := make([]*PubSub, 2)
|
||||||
@ -2886,6 +2886,67 @@ func TestGossipsubNoIDONTWANTToMessageSender(t *testing.T) {
|
|||||||
t.Fatal("IDONTWANT should not be sent to the message sender")
|
t.Fatal("IDONTWANT should not be sent to the message sender")
|
||||||
case <-time.After(time.Second):
|
case <-time.After(time.Second):
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGossipsubIDONTWANTBeforeFirstPublish(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
hosts := getDefaultHosts(t, 2)
|
||||||
|
denseConnect(t, hosts)
|
||||||
|
|
||||||
|
psubs := make([]*PubSub, 2)
|
||||||
|
|
||||||
|
psubs[0] = getGossipsub(ctx, hosts[0])
|
||||||
|
rpcsReceived := make(chan string)
|
||||||
|
psubs[1] = getGossipsub(ctx, hosts[1], WithRawTracer(&mockRawTracer{
|
||||||
|
onRecvRPC: func(rpc *RPC) {
|
||||||
|
if len(rpc.GetControl().GetIdontwant()) > 0 {
|
||||||
|
rpcsReceived <- "idontwant"
|
||||||
|
}
|
||||||
|
if len(rpc.GetPublish()) > 0 {
|
||||||
|
rpcsReceived <- "publish"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
topicString := "foobar"
|
||||||
|
var topics []*Topic
|
||||||
|
for _, ps := range psubs {
|
||||||
|
topic, err := ps.Join(topicString)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
topics = append(topics, topic)
|
||||||
|
|
||||||
|
_, err = ps.Subscribe(topicString)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
|
msg := make([]byte, GossipSubIDontWantMessageThreshold+1)
|
||||||
|
_ = topics[0].Publish(ctx, msg)
|
||||||
|
|
||||||
|
timeout := time.After(5 * time.Second)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case kind := <-rpcsReceived:
|
||||||
|
if kind == "publish" {
|
||||||
|
t.Fatal("IDONTWANT should be sent before publish")
|
||||||
|
}
|
||||||
|
case <-timeout:
|
||||||
|
t.Fatal("IDONTWANT should be sent on first publish")
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case kind := <-rpcsReceived:
|
||||||
|
if kind != "publish" {
|
||||||
|
t.Fatal("Expected publish after IDONTWANT")
|
||||||
|
}
|
||||||
|
case <-timeout:
|
||||||
|
t.Fatal("Expected publish after IDONTWANT")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -204,9 +204,9 @@ type PubSubRouter interface {
|
|||||||
// Allows routers with internal scoring to vet peers before committing any processing resources
|
// Allows routers with internal scoring to vet peers before committing any processing resources
|
||||||
// to the message and implement an effective graylist and react to validation queue overload.
|
// to the message and implement an effective graylist and react to validation queue overload.
|
||||||
AcceptFrom(peer.ID) AcceptStatus
|
AcceptFrom(peer.ID) AcceptStatus
|
||||||
// PreValidation is invoked on messages in the RPC envelope right before pushing it to
|
// Preprocess is invoked on messages in the RPC envelope right before pushing it to
|
||||||
// the validation pipeline
|
// the validation pipeline
|
||||||
PreValidation(from peer.ID, msgs []*Message)
|
Preprocess(from peer.ID, msgs []*Message)
|
||||||
// HandleRPC is invoked to process control messages in the RPC envelope.
|
// HandleRPC is invoked to process control messages in the RPC envelope.
|
||||||
// It is invoked after subscriptions and payload messages have been processed.
|
// It is invoked after subscriptions and payload messages have been processed.
|
||||||
HandleRPC(*RPC)
|
HandleRPC(*RPC)
|
||||||
@ -1117,7 +1117,7 @@ func (p *PubSub) handleIncomingRPC(rpc *RPC) {
|
|||||||
toPush = append(toPush, msg)
|
toPush = append(toPush, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.rt.PreValidation(rpc.from, toPush)
|
p.rt.Preprocess(rpc.from, toPush)
|
||||||
for _, msg := range toPush {
|
for _, msg := range toPush {
|
||||||
p.pushMsg(msg)
|
p.pushMsg(msg)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -94,7 +94,7 @@ func (rs *RandomSubRouter) AcceptFrom(peer.ID) AcceptStatus {
|
|||||||
return AcceptAll
|
return AcceptAll
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *RandomSubRouter) PreValidation(from peer.ID, msgs []*Message) {}
|
func (rs *RandomSubRouter) Preprocess(from peer.ID, msgs []*Message) {}
|
||||||
|
|
||||||
func (rs *RandomSubRouter) HandleRPC(rpc *RPC) {}
|
func (rs *RandomSubRouter) HandleRPC(rpc *RPC) {}
|
||||||
|
|
||||||
|
|||||||
1
topic.go
1
topic.go
@ -349,6 +349,7 @@ func (t *Topic) validate(ctx context.Context, data []byte, opts ...PubOpt) (*Mes
|
|||||||
}
|
}
|
||||||
|
|
||||||
msg := &Message{m, "", t.p.host.ID(), pub.validatorData, pub.local}
|
msg := &Message{m, "", t.p.host.ID(), pub.validatorData, pub.local}
|
||||||
|
t.p.rt.Preprocess(t.p.host.ID(), []*Message{msg})
|
||||||
err := t.p.val.ValidateLocal(msg)
|
err := t.p.val.ValidateLocal(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user