From 6d0430871637140ce0b00a13631f296a54da06cc Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Wed, 10 Nov 2021 10:28:45 -0400 Subject: [PATCH] feat: 23/WAKU2-TOPICS (#146) --- README.md | 2 +- examples/basic2/go.mod | 2 +- examples/basic2/go.sum | 3 +- examples/basic2/main.go | 6 +- examples/chat2/chat.go | 3 +- examples/chat2/go.mod | 2 +- examples/chat2/go.sum | 3 +- examples/chat2/main.go | 4 +- examples/filter2/go.mod | 2 +- examples/filter2/go.sum | 3 +- examples/filter2/main.go | 14 +++-- waku/v2/protocol/relay/waku_relay.go | 3 +- waku/v2/protocol/topic.go | 91 ++++++++++++++++++++++++++++ waku/v2/protocol/topic_test.go | 57 +++++++++++++++++ 14 files changed, 174 insertions(+), 21 deletions(-) create mode 100644 waku/v2/protocol/topic.go create mode 100644 waku/v2/protocol/topic_test.go diff --git a/README.md b/README.md index 901959e3..21820e09 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ Examples of usage of go-waku as a library can be found in the examples folder. T |[18/WAKU2-SWAP](https://rfc.vac.dev/spec/18)|| |[21/WAKU2-FTSTORE](https://rfc.vac.dev/spec/21)|✔| |[22/TOY-CHAT](https://rfc.vac.dev/spec/22)|✔| -|[23/TOPICS](https://rfc.vac.dev/spec/22)|(implemented in status-go)| +|[23/TOPICS](https://rfc.vac.dev/spec/22)|✔| |[25/LIBP2P-DNS-DISCOVERY](https://rfc.vac.dev/spec/25)|🚧| |[26/WAKU2-PAYLOAD](https://rfc.vac.dev/spec/26)|✔| |[27/WAKU2-PEERS](https://rfc.vac.dev/spec/27)|✔| diff --git a/examples/basic2/go.mod b/examples/basic2/go.mod index 3980ce70..eb0f0d36 100644 --- a/examples/basic2/go.mod +++ b/examples/basic2/go.mod @@ -2,7 +2,7 @@ module basic2 go 1.15 -// replace github.com/status-im/go-waku => ../.. +replace github.com/status-im/go-waku => ../.. require ( github.com/ethereum/go-ethereum v1.10.9 diff --git a/examples/basic2/go.sum b/examples/basic2/go.sum index 99c829d4..d3426458 100644 --- a/examples/basic2/go.sum +++ b/examples/basic2/go.sum @@ -353,6 +353,7 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= @@ -1053,8 +1054,6 @@ github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= -github.com/status-im/go-waku v0.0.0-20211101194039-94e8b9cf86fc h1:u410QB8K5iFXaI4FYh2JR7A2oCHlXD4CLnI5/gJei9Q= -github.com/status-im/go-waku v0.0.0-20211101194039-94e8b9cf86fc/go.mod h1:A0lI3uZYLKrXiviVkwGgBdT8b9HLcW3U/xUcE/4665k= github.com/status-im/go-waku-rendezvous v0.0.0-20211018070416-a93f3b70c432 h1:cbNFU38iimo9fY4B7CdF/fvIF6tNPJIZjBbpfmW2EY4= github.com/status-im/go-waku-rendezvous v0.0.0-20211018070416-a93f3b70c432/go.mod h1:A8t3i0CUGtXCA0aiLsP7iyikmk/KaD/2XVvNJqGCU20= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= diff --git a/examples/basic2/main.go b/examples/basic2/main.go index 980e03b8..96cdb229 100644 --- a/examples/basic2/main.go +++ b/examples/basic2/main.go @@ -14,6 +14,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" logging "github.com/ipfs/go-log" "github.com/status-im/go-waku/waku/v2/node" + "github.com/status-im/go-waku/waku/v2/protocol" "github.com/status-im/go-waku/waku/v2/protocol/pb" "github.com/status-im/go-waku/waku/v2/utils" ) @@ -80,7 +81,8 @@ func randomHex(n int) (string, error) { } func write(ctx context.Context, wakuNode *node.WakuNode, msgContent string) { - var contentTopic string = "test" + contentTopic := protocol.NewContentTopic("basic2", 1, "test", "proto") + var version uint32 = 0 var timestamp float64 = utils.GetUnixEpoch() @@ -97,7 +99,7 @@ func write(ctx context.Context, wakuNode *node.WakuNode, msgContent string) { msg := &pb.WakuMessage{ Payload: payload, Version: version, - ContentTopic: contentTopic, + ContentTopic: contentTopic.String(), Timestamp: timestamp, } diff --git a/examples/chat2/chat.go b/examples/chat2/chat.go index dbfd7dd2..dcb95f76 100644 --- a/examples/chat2/chat.go +++ b/examples/chat2/chat.go @@ -55,7 +55,8 @@ func NewChat(ctx context.Context, n *node.WakuNode, selfID peer.ID, contentTopic ContentTopics: []string{contentTopic}, } var err error - _, chat.C, err = n.SubscribeFilter(ctx, cf) + _, theFilter, err := n.Filter().Subscribe(ctx, cf) + chat.C = theFilter.Chan if err != nil { return nil, err } diff --git a/examples/chat2/go.mod b/examples/chat2/go.mod index 40a4bbb5..1aaba858 100644 --- a/examples/chat2/go.mod +++ b/examples/chat2/go.mod @@ -2,7 +2,7 @@ module chat2 go 1.15 -// replace github.com/status-im/go-waku => ../.. +replace github.com/status-im/go-waku => ../.. require ( github.com/ethereum/go-ethereum v1.10.9 diff --git a/examples/chat2/go.sum b/examples/chat2/go.sum index eeafddc9..8e33931c 100644 --- a/examples/chat2/go.sum +++ b/examples/chat2/go.sum @@ -359,6 +359,7 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= @@ -1070,8 +1071,6 @@ github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= -github.com/status-im/go-waku v0.0.0-20211101194039-94e8b9cf86fc h1:u410QB8K5iFXaI4FYh2JR7A2oCHlXD4CLnI5/gJei9Q= -github.com/status-im/go-waku v0.0.0-20211101194039-94e8b9cf86fc/go.mod h1:A0lI3uZYLKrXiviVkwGgBdT8b9HLcW3U/xUcE/4665k= github.com/status-im/go-waku-rendezvous v0.0.0-20211018070416-a93f3b70c432 h1:cbNFU38iimo9fY4B7CdF/fvIF6tNPJIZjBbpfmW2EY4= github.com/status-im/go-waku-rendezvous v0.0.0-20211018070416-a93f3b70c432/go.mod h1:A8t3i0CUGtXCA0aiLsP7iyikmk/KaD/2XVvNJqGCU20= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= diff --git a/examples/chat2/main.go b/examples/chat2/main.go index f76d7d0c..69e27f9a 100644 --- a/examples/chat2/main.go +++ b/examples/chat2/main.go @@ -20,6 +20,8 @@ import ( logging "github.com/ipfs/go-log" "github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/protocol" + wakuprotocol "github.com/status-im/go-waku/waku/v2/protocol" + "github.com/multiformats/go-multiaddr" "github.com/status-im/go-waku/waku/v2/discovery" "github.com/status-im/go-waku/waku/v2/node" @@ -28,7 +30,7 @@ import ( "github.com/status-im/go-waku/waku/v2/protocol/store" ) -var DefaultContentTopic string = "/toy-chat/2/huilong/proto" +var DefaultContentTopic string = wakuprotocol.NewContentTopic("toy-chat", 2, "huilong", "proto").String() func main() { mrand.Seed(time.Now().UTC().UnixNano()) diff --git a/examples/filter2/go.mod b/examples/filter2/go.mod index d42af18d..0d0232f1 100644 --- a/examples/filter2/go.mod +++ b/examples/filter2/go.mod @@ -2,7 +2,7 @@ module filter2 go 1.15 -// replace github.com/status-im/go-waku => ../.. +replace github.com/status-im/go-waku => ../.. require ( github.com/ethereum/go-ethereum v1.10.9 diff --git a/examples/filter2/go.sum b/examples/filter2/go.sum index 99c829d4..d3426458 100644 --- a/examples/filter2/go.sum +++ b/examples/filter2/go.sum @@ -353,6 +353,7 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= @@ -1053,8 +1054,6 @@ github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= -github.com/status-im/go-waku v0.0.0-20211101194039-94e8b9cf86fc h1:u410QB8K5iFXaI4FYh2JR7A2oCHlXD4CLnI5/gJei9Q= -github.com/status-im/go-waku v0.0.0-20211101194039-94e8b9cf86fc/go.mod h1:A0lI3uZYLKrXiviVkwGgBdT8b9HLcW3U/xUcE/4665k= github.com/status-im/go-waku-rendezvous v0.0.0-20211018070416-a93f3b70c432 h1:cbNFU38iimo9fY4B7CdF/fvIF6tNPJIZjBbpfmW2EY4= github.com/status-im/go-waku-rendezvous v0.0.0-20211018070416-a93f3b70c432/go.mod h1:A8t3i0CUGtXCA0aiLsP7iyikmk/KaD/2XVvNJqGCU20= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= diff --git a/examples/filter2/main.go b/examples/filter2/main.go index 2134754f..aaf9fd23 100644 --- a/examples/filter2/main.go +++ b/examples/filter2/main.go @@ -14,6 +14,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" logging "github.com/ipfs/go-log" "github.com/status-im/go-waku/waku/v2/node" + "github.com/status-im/go-waku/waku/v2/protocol" "github.com/status-im/go-waku/waku/v2/protocol/filter" "github.com/status-im/go-waku/waku/v2/protocol/pb" "github.com/status-im/go-waku/waku/v2/protocol/relay" @@ -22,7 +23,7 @@ import ( var log = logging.Logger("filter2") -var pubSubTopic = relay.DefaultWakuTopic +var pubSubTopic = protocol.DefaultPubsubTopic() const contentTopic = "test" @@ -98,17 +99,17 @@ func main() { // Send FilterRequest from light node to full node cf := filter.ContentFilter{ - Topic: string(pubSubTopic), + Topic: pubSubTopic.String(), ContentTopics: []string{contentTopic}, } - _, filterChan, err := lightNode.SubscribeFilter(ctx, cf) + _, theFilter, err := lightNode.Filter().Subscribe(ctx, cf) if err != nil { panic(err) } go func() { - for env := range filterChan { + for env := range theFilter.Chan { log.Info("Light node received msg, ", string(env.Message().Payload)) } log.Info("Message channel closed!") @@ -120,7 +121,7 @@ func main() { go func() { // Unsubscribe filter after 5 seconds time.Sleep(5 * time.Second) - lightNode.UnsubscribeFilter(ctx, cf) + lightNode.Filter().UnsubscribeFilter(ctx, cf) }() // Wait for a SIGINT or SIGTERM signal ch := make(chan os.Signal, 1) @@ -172,7 +173,8 @@ func writeLoop(ctx context.Context, wakuNode *node.WakuNode) { } func readLoop(ctx context.Context, wakuNode *node.WakuNode) { - sub, err := wakuNode.Relay().Subscribe(ctx, &pubSubTopic) + pubsubTopic := relay.Topic(pubSubTopic.String()) + sub, err := wakuNode.Relay().Subscribe(ctx, &pubsubTopic) if err != nil { log.Error("Could not subscribe: ", err) return diff --git a/waku/v2/protocol/relay/waku_relay.go b/waku/v2/protocol/relay/waku_relay.go index 8e4c7932..be1e2cf4 100644 --- a/waku/v2/protocol/relay/waku_relay.go +++ b/waku/v2/protocol/relay/waku_relay.go @@ -27,7 +27,8 @@ var log = logging.Logger("wakurelay") type Topic string const WakuRelayID_v200 = protocol.ID("/vac/waku/relay/2.0.0") -const DefaultWakuTopic Topic = "/waku/2/default-waku/proto" + +var DefaultWakuTopic Topic = Topic(waku_proto.DefaultPubsubTopic().String()) type WakuRelay struct { host host.Host diff --git a/waku/v2/protocol/topic.go b/waku/v2/protocol/topic.go new file mode 100644 index 00000000..2c9aba4f --- /dev/null +++ b/waku/v2/protocol/topic.go @@ -0,0 +1,91 @@ +package protocol + +import ( + "errors" + "fmt" + "strconv" + "strings" +) + +var ErrInvalidFormat = errors.New("invalid format") + +type ContentTopic struct { + ApplicationName string + ApplicationVersion uint + ContentTopicName string + Encoding string +} + +func (ct ContentTopic) String() string { + return fmt.Sprintf("/%s/%d/%s/%s", ct.ApplicationName, ct.ApplicationVersion, ct.ContentTopicName, ct.Encoding) +} + +func NewContentTopic(applicationName string, applicationVersion uint, contentTopicName string, encoding string) ContentTopic { + return ContentTopic{ + ApplicationName: applicationName, + ApplicationVersion: applicationVersion, + ContentTopicName: contentTopicName, + Encoding: encoding, + } +} + +func (ct ContentTopic) Equal(ct2 ContentTopic) bool { + return ct.ApplicationName == ct2.ApplicationName && ct.ApplicationVersion == ct2.ApplicationVersion && + ct.ContentTopicName == ct2.ContentTopicName && ct.Encoding == ct2.Encoding +} + +func StringToContentTopic(s string) (ContentTopic, error) { + p := strings.Split(s, "/") + + if len(p) != 5 || p[0] != "" || p[1] == "" || p[2] == "" || p[3] == "" || p[4] == "" { + return ContentTopic{}, ErrInvalidFormat + } + + vNum, err := strconv.ParseUint(p[2], 10, 32) + if err != nil { + return ContentTopic{}, ErrInvalidFormat + } + + return ContentTopic{ + ApplicationName: p[1], + ApplicationVersion: uint(vNum), + ContentTopicName: p[3], + Encoding: p[4], + }, nil +} + +type PubsubTopic struct { + Name string + Encoding string +} + +func (t PubsubTopic) String() string { + return fmt.Sprintf("/waku/2/%s/%s", t.Name, t.Encoding) +} + +func DefaultPubsubTopic() PubsubTopic { + return NewPubsubTopic("default-waku", "proto") +} + +func NewPubsubTopic(name string, encoding string) PubsubTopic { + return PubsubTopic{ + Name: name, + Encoding: encoding, + } +} + +func (t PubsubTopic) Equal(t2 PubsubTopic) bool { + return t.Name == t2.Name && t.Encoding == t2.Encoding +} + +func StringToPubsubTopic(s string) (PubsubTopic, error) { + p := strings.Split(s, "/") + if len(p) != 5 || p[0] != "" || p[1] != "waku" || p[2] != "2" || p[3] == "" || p[4] == "" { + return PubsubTopic{}, ErrInvalidFormat + } + + return PubsubTopic{ + Name: p[3], + Encoding: p[4], + }, nil +} diff --git a/waku/v2/protocol/topic_test.go b/waku/v2/protocol/topic_test.go new file mode 100644 index 00000000..07cd2de7 --- /dev/null +++ b/waku/v2/protocol/topic_test.go @@ -0,0 +1,57 @@ +package protocol + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestContentTopic(t *testing.T) { + ct := NewContentTopic("waku", 2, "test", "proto") + require.Equal(t, ct.String(), "/waku/2/test/proto") + + _, err := StringToContentTopic("/waku/-1/a/b") + require.Error(t, ErrInvalidFormat, err) + + _, err = StringToContentTopic("waku/1/a/b") + require.Error(t, ErrInvalidFormat, err) + + _, err = StringToContentTopic("////") + require.Error(t, ErrInvalidFormat, err) + + _, err = StringToContentTopic("/waku/1/a") + require.Error(t, ErrInvalidFormat, err) + + ct2, err := StringToContentTopic("/waku/2/test/proto") + require.NoError(t, err) + require.Equal(t, ct.String(), ct2.String()) + require.True(t, ct.Equal(ct2)) + + ct3 := NewContentTopic("waku", 2, "test2", "proto") + require.False(t, ct.Equal(ct3)) +} + +func TestTopic(t *testing.T) { + topic := NewPubsubTopic("test", "proto") + require.Equal(t, topic.String(), "/waku/2/test/proto") + + _, err := StringToPubsubTopic("/waku/-1/a/b") + require.Error(t, ErrInvalidFormat, err) + + _, err = StringToPubsubTopic("waku/2/a/b") + require.Error(t, ErrInvalidFormat, err) + + _, err = StringToPubsubTopic("////") + require.Error(t, ErrInvalidFormat, err) + + _, err = StringToPubsubTopic("/waku/2/a") + require.Error(t, ErrInvalidFormat, err) + + topic2, err := StringToPubsubTopic("/waku/2/test/proto") + require.NoError(t, err) + require.Equal(t, topic.String(), topic2.String()) + require.True(t, topic.Equal(topic2)) + + topic3 := NewPubsubTopic("test2", "proto") + require.False(t, topic.Equal(topic3)) +}