diff --git a/Makefile b/Makefile index faade6a1..005a4741 100644 --- a/Makefile +++ b/Makefile @@ -38,12 +38,18 @@ BUILD_FLAGS ?= $(shell echo "-ldflags='\ -X github.com/status-im/go-waku/waku/v2/node.GitCommit=$(GIT_COMMIT) \ -X github.com/status-im/go-waku/waku/v2/node.Version=$(VERSION)'") + +# control rln code compilation +ifeq ($(RLN), true) +BUILD_TAGS := gowaku_rln +endif + all: build deps: lint-install build: - ${GOBIN} build $(BUILD_FLAGS) -o build/waku waku.go + ${GOBIN} build -tags="${BUILD_TAGS}" $(BUILD_FLAGS) -o build/waku vendor: ${GOBIN} mod tidy @@ -105,6 +111,7 @@ static-library: @echo "Building static library..." ${GOBIN} build \ -buildmode=c-archive \ + -tags="${BUILD_TAGS}" \ -o ./build/lib/libgowaku.a \ ./library/ @echo "Static library built:" @@ -114,6 +121,7 @@ dynamic-library: @echo "Building shared library..." $(GOBIN_SHARED_LIB_CFLAGS) $(GOBIN_SHARED_LIB_CGO_LDFLAGS) ${GOBIN} build \ -buildmode=c-shared \ + -tags="${BUILD_TAGS}" \ -o ./build/lib/libgowaku.$(GOBIN_SHARED_LIB_EXT) \ ./library/ ifeq ($(detected_OS),Linux) @@ -128,14 +136,14 @@ endif mobile-android: gomobile init && \ go get -d golang.org/x/mobile/cmd/gomobile && \ - gomobile bind -v -target=android -ldflags="-s -w" $(BUILD_FLAGS) -o ./build/lib/gowaku.aar ./mobile + gomobile bind -v -target=android -ldflags="-s -w" -tags="${BUILD_TAGS}" $(BUILD_FLAGS) -o ./build/lib/gowaku.aar ./mobile @echo "Android library built:" @ls -la ./build/lib/*.aar ./build/lib/*.jar mobile-ios: gomobile init && \ go get -d golang.org/x/mobile/cmd/gomobile && \ - gomobile bind -target=ios -ldflags="-s -w" -o ./build/lib/Gowaku.xcframework ./mobile + gomobile bind -target=ios -ldflags="-s -w" -tags="${BUILD_TAGS}" $(BUILD_FLAGS) -o ./build/lib/Gowaku.xcframework ./mobile @echo "IOS library built:" @ls -la ./build/lib/*.xcframework @@ -158,6 +166,7 @@ start-ganache: stop-ganache: docker stop ganache-cli +test-onchain: BUILD_TAGS += include_onchain_tests test-onchain: - ${GOBIN} test -v -count 1 -tags="include_onchain_tests" github.com/status-im/go-waku/waku/v2/protocol/rln + ${GOBIN} test -v -count 1 -tags="${BUILD_TAGS}" github.com/status-im/go-waku/waku/v2/protocol/rln diff --git a/go.mod b/go.mod index 9bdcd20e..adc03eef 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( require ( github.com/flynn/noise v1.0.0 github.com/gorilla/mux v1.8.0 - github.com/status-im/go-rln v0.0.8 + github.com/status-im/go-rln v0.0.9 golang.org/x/text v0.3.7 ) diff --git a/go.sum b/go.sum index 686aada7..d7b0178d 100644 --- a/go.sum +++ b/go.sum @@ -1693,8 +1693,8 @@ github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5q github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= github.com/status-im/go-discover v0.0.0-20220406135310-85a2ce36f63e h1:fDm8hqKGFy8LMNV8zedT3W+QYVPVDfb0F9Fr7fVf9rQ= github.com/status-im/go-discover v0.0.0-20220406135310-85a2ce36f63e/go.mod h1:u1s0ACIlweIjmJrgXyljRPSOflZLaS6ezb044+92W3c= -github.com/status-im/go-rln v0.0.8 h1:OD27bZFUFhfd9ZkE715wEozv5DCueE0i9Z9a0qwCzog= -github.com/status-im/go-rln v0.0.8/go.mod h1:t8Bf4nNAuQh9VlEiz/rgFVtEz7sjEfcd62MIuEnZn8U= +github.com/status-im/go-rln v0.0.9 h1:qDmFJoFS/1PGNDB0pEjlRDRNZUpIFBAde2f3fIixCbA= +github.com/status-im/go-rln v0.0.9/go.mod h1:t8Bf4nNAuQh9VlEiz/rgFVtEz7sjEfcd62MIuEnZn8U= 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/go-watchdog v1.2.0-ios-nolibproc h1:BJwZEF7OVKaXc2zErBUAolFSGzwrTBbWnN8e/6MER5E= diff --git a/waku.go b/waku.go index b2587503..8b6de47d 100644 --- a/waku.go +++ b/waku.go @@ -12,479 +12,421 @@ import ( var options waku.Options func main() { - app := &cli.App{ - Flags: []cli.Flag{ - &cli.IntFlag{ - Name: "tcp-port", - Aliases: []string{"port", "p"}, - Value: 60000, - Usage: "Libp2p TCP listening port (0 for random)", - Destination: &options.Port, - }, - &cli.StringFlag{ - Name: "address", - Aliases: []string{"host", "listen-address"}, - Value: "0.0.0.0", - Usage: "Listening address", - Destination: &options.Address, - }, - &cli.BoolFlag{ - Name: "websocket-support", - Aliases: []string{"ws"}, - Usage: "Enable websockets support", - Destination: &options.Websocket.Enable, - }, - &cli.IntFlag{ - Name: "websocket-port", - Aliases: []string{"ws-port"}, - Value: 60001, - Usage: "Libp2p TCP listening port for websocket connection (0 for random)", - Destination: &options.Websocket.Port, - }, - &cli.StringFlag{ - Name: "websocket-address", - Aliases: []string{"ws-address"}, - Value: "0.0.0.0", - Usage: "Listening address for websocket connections", - Destination: &options.Websocket.Address, - }, - &cli.BoolFlag{ - Name: "websocket-secure-support", - Aliases: []string{"wss"}, - Usage: "Enable secure websockets support", - Destination: &options.Websocket.Secure, - }, - &cli.StringFlag{ - Name: "websocket-secure-key-path", - Aliases: []string{"wss-key"}, - Value: "/path/to/key.txt", - Usage: "Secure websocket key path", - Destination: &options.Websocket.KeyPath, - }, - &cli.StringFlag{ - Name: "websocket-secure-cert-path", - Aliases: []string{"wss-cert"}, - Value: "/path/to/cert.txt", - Usage: "Secure websocket certificate path", - Destination: &options.Websocket.CertPath, - }, - &cli.StringFlag{ - Name: "dns4-domain-name", - Value: "", - Usage: "The domain name resolving to the node's public IPv4 address", - Destination: &options.Dns4DomainName, - }, - &cli.StringFlag{ - Name: "nodekey", - Usage: "P2P node private key as hex. Can also be set with GOWAKU-NODEKEY env variable (default random)", - Destination: &options.NodeKey, - }, - &cli.StringFlag{ - Name: "key-file", - Value: "./nodekey", - Usage: "Path to a file containing the private key for the P2P node", - Destination: &options.KeyFile, - }, - &cli.StringFlag{ - Name: "key-password", - Value: "secret", - Usage: "Password used for the private key file", - Destination: &options.KeyPasswd, - }, - &cli.BoolFlag{ - Name: "generate-key", - Usage: "Generate private key file at path specified in --key-file with the password defined by --key-password", - Destination: &options.GenerateKey, - }, - &cli.BoolFlag{ - Name: "overwrite", - Usage: "When generating a keyfile, overwrite the nodekey file if it already exists", - Destination: &options.Overwrite, - }, - &cli.StringSliceFlag{ - Name: "staticnode", - Usage: "Multiaddr of peer to directly connect with. Option may be repeated", - Destination: &options.StaticNodes, - }, - &cli.IntFlag{ - Name: "keep-alive", - Value: 20, - Usage: "Interval in seconds for pinging peers to keep the connection alive.", - Destination: &options.KeepAlive, - }, - &cli.BoolFlag{ - Name: "use-db", - Aliases: []string{"sqlite-store"}, - Usage: "Use SQLiteDB to persist information", - Destination: &options.UseDB, - }, - &cli.BoolFlag{ - Name: "persist-messages", - Usage: "Enable message persistence", - Destination: &options.Store.PersistMessages, - Value: false, - }, - &cli.BoolFlag{ - Name: "persist-peers", - Usage: "Enable peer persistence", - Destination: &options.PersistPeers, - Value: false, - }, - &cli.StringFlag{ - Name: "nat", // This was added so js-waku test don't fail - Usage: "TODO: Not implemented yet. Specify method to use for determining public address: any, none ('any' will attempt upnp/pmp)", - Value: "any", - Destination: &options.NAT, // TODO: accept none,any,upnp,extaddr - }, - &cli.StringFlag{ - Name: "db-path", - Aliases: []string{"dbpath"}, - Value: "./store.db", - Usage: "Path to DB file", - Destination: &options.DBPath, - }, - &cli.StringFlag{ - Name: "advertise-address", - Usage: "External address to advertise to other nodes (overrides --address and --ws-address flags)", - Destination: &options.AdvertiseAddress, - }, - &cli.BoolFlag{ - Name: "show-addresses", - Usage: "Display listening addresses according to current configuration", - Destination: &options.ShowAddresses, - }, - &cli.StringFlag{ - Name: "log-level", - Aliases: []string{"l"}, - Value: "INFO", - Usage: "Define the logging level, supported strings are: DEBUG, INFO, WARN, ERROR, DPANIC, PANIC, FATAL, and their lower-case forms.", - Destination: &options.LogLevel, - }, - &cli.BoolFlag{ - Name: "version", - Value: false, - Usage: "prints the version", - Destination: &options.Version, - }, - &cli.StringFlag{ - Name: "log-encoding", - Value: "console", - Usage: "Define the encoding used for the logs: console, json", - Destination: &options.LogEncoding, - }, - &cli.BoolFlag{ - Name: "relay", - Value: true, - Usage: "Enable relay protocol", - Destination: &options.Relay.Enable, - }, - &cli.StringSliceFlag{ - Name: "topics", - Usage: "List of topics to listen", - Destination: &options.Relay.Topics, - }, - &cli.BoolFlag{ - Name: "relay-peer-exchange", - Aliases: []string{"peer-exchange"}, - Value: false, - Usage: "Enable GossipSub Peer Exchange", - Destination: &options.Relay.PeerExchange, - }, - &cli.IntFlag{ - Name: "min-relay-peers-to-publish", - Value: 1, - Usage: "Minimum number of peers to publish to Relay", - Destination: &options.Relay.MinRelayPeersToPublish, - }, - &cli.BoolFlag{ - Name: "store", - Usage: "Enable relay protocol", - Destination: &options.Store.Enable, - }, - &cli.BoolFlag{ - Name: "resume", - Usage: "Fix the gaps in message history", - Destination: &options.Store.ShouldResume, - }, - &cli.IntFlag{ - Name: "store-seconds", - Value: (86400 * 30), // 30 days - Usage: "maximum number of seconds before a message is removed from the store", - Destination: &options.Store.RetentionMaxSeconds, - }, - &cli.IntFlag{ - Name: "store-capacity", - Value: 50000, - Usage: "maximum number of messages to store", - Destination: &options.Store.RetentionMaxMessages, - }, - &cli.StringSliceFlag{ - Name: "storenode", - Usage: "Multiaddr of a peer that supports store protocol. Option may be repeated", - Destination: &options.Store.Nodes, - }, - &cli.BoolFlag{ - Name: "swap", - Usage: "Enable swap protocol", - Value: false, - Destination: &options.Swap.Enable, - }, - &cli.IntFlag{ - Name: "swap-mode", - Value: 0, - Usage: "Swap mode: 0=soft, 1=mock, 2=hard", - Destination: &options.Swap.Mode, - }, - &cli.IntFlag{ - Name: "swap-payment-threshold", - Value: 100, - Usage: "Threshold for payment", - Destination: &options.Swap.PaymentThreshold, - }, - &cli.IntFlag{ - Name: "swap-disconnect-threshold", - Value: -100, - Usage: "Threshold for disconnecting", - Destination: &options.Swap.DisconnectThreshold, - }, - &cli.BoolFlag{ - Name: "filter", - Usage: "Enable filter protocol", - Destination: &options.Filter.Enable, - }, - &cli.BoolFlag{ - Name: "light-client", - Usage: "Don't accept filter subscribers", - Destination: &options.Filter.DisableFullNode, - }, - &cli.StringSliceFlag{ - Name: "filternode", - Usage: "Multiaddr of a peer that supports filter protocol. Option may be repeated", - Destination: &options.Filter.Nodes, - }, - &cli.IntFlag{ - Name: "filter-timeout", - Value: 14400, - Usage: "Timeout for filter node in seconds", - Destination: &options.Filter.Timeout, - }, - &cli.BoolFlag{ - Name: "lightpush", - Usage: "Enable lightpush protocol", - Destination: &options.LightPush.Enable, - }, - &cli.StringSliceFlag{ - Name: "lightpushnode", - Usage: "Multiaddr of a peer that supports lightpush protocol. Option may be repeated", - Destination: &options.LightPush.Nodes, - }, - &cli.BoolFlag{ - Name: "rln-relay", - Value: false, - Usage: "Enable spam protection through rln-relay", - Destination: &options.RLNRelay.Enable, - }, - &cli.IntFlag{ - Name: "rln-relay-membership-index", - Value: 0, - Usage: "(experimental) the index of node in the rln-relay group: a value between 0-99 inclusive", - Destination: &options.RLNRelay.MembershipIndex, - }, - &cli.StringFlag{ - Name: "rln-relay-pubsub-topic", - Value: "/waku/2/default-waku/proto", - Usage: "the pubsub topic for which rln-relay gets enabled", - Destination: &options.RLNRelay.PubsubTopic, - }, - &cli.StringFlag{ - Name: "rln-relay-content-topic", - Value: "/toy-chat/2/luzhou/proto", - Usage: "the content topic for which rln-relay gets enabled", - Destination: &options.RLNRelay.ContentTopic, - }, - &cli.BoolFlag{ - Name: "rln-relay-dynamic", - Usage: "Enable waku-rln-relay with on-chain dynamic group management", - Destination: &options.RLNRelay.Dynamic, - }, - &cli.StringFlag{ - Name: "rln-relay-id", - Usage: "Rln relay identity secret key as a Hex string", - Destination: &options.RLNRelay.IDKey, - }, - &cli.StringFlag{ - Name: "rln-relay-id-commitment", - Usage: "Rln relay identity commitment key as a Hex string", - Destination: &options.RLNRelay.IDCommitment, - }, - &cli.StringFlag{ - Name: "rln-relay-membership-credentials-file", - Usage: "RLN relay membership credentials file", - Value: "rlnCredentials.txt", - Destination: &options.RLNRelay.CredentialsFile, - }, - // TODO: this is a good candidate option for subcommands - // TODO: consider accepting a private key file and passwd - &cli.StringFlag{ - Name: "eth-private-key", - Usage: "Ethereum Goerli testnet account private key used for registering in member contract", - Destination: &options.RLNRelay.ETHPrivateKey, - }, - &cli.StringFlag{ - Name: "eth-client-address", - Usage: "Ethereum testnet client address", - Value: "ws://localhost:8545", - Destination: &options.RLNRelay.ETHClientAddress, - }, - &cli.StringFlag{ - Name: "eth-mem-contract-address", - Usage: "Address of membership contract on an Ethereum testnet", - Destination: &options.RLNRelay.MembershipContractAddress, - }, - &cli.BoolFlag{ - Name: "discv5-discovery", - Usage: "Enable discovering nodes via Node Discovery v5", - Destination: &options.DiscV5.Enable, - }, - &cli.StringSliceFlag{ - Name: "discv5-bootstrap-node", - Usage: "Text-encoded ENR for bootstrap node. Used when connecting to the network. Option may be repeated", - Destination: &options.DiscV5.Nodes, - }, - &cli.IntFlag{ - Name: "discv5-udp-port", - Value: 9000, - Usage: "Listening UDP port for Node Discovery v5.", - Destination: &options.DiscV5.Port, - }, - &cli.BoolFlag{ - Name: "discv5-enr-auto-update", - Usage: "Discovery can automatically update its ENR with the IP address as seen by other nodes it communicates with.", - Destination: &options.DiscV5.AutoUpdate, - }, - &cli.BoolFlag{ - Name: "rendezvous", - Usage: "Enable rendezvous protocol for peer discovery", - Destination: &options.Rendezvous.Enable, - }, - &cli.StringSliceFlag{ - Name: "rendezvous-node", - Usage: "Multiaddr of a waku2 rendezvous node. Option may be repeated", - Destination: &options.Rendezvous.Nodes, - }, - &cli.BoolFlag{ - Name: "rendezvous-server", - Usage: "Node will act as rendezvous server", - Destination: &options.RendezvousServer.Enable, - }, - &cli.StringFlag{ - Name: "rendezvous-db-path", - Value: "/tmp/rendezvous", - Usage: "Path where peer records database will be stored", - Destination: &options.RendezvousServer.DBPath, - }, - &cli.BoolFlag{ - Name: "dns-discovery", - Usage: "Enable DNS discovery", - Destination: &options.DNSDiscovery.Enable, - }, - &cli.StringFlag{ - Name: "dns-discovery-url", - Usage: "URL for DNS node list in format 'enrtree://@'", - Destination: &options.DNSDiscovery.URL, - }, - &cli.StringFlag{ - Name: "dns-discovery-name-server", - Aliases: []string{"dns-discovery-nameserver"}, - Usage: "DNS nameserver IP to query (empty to use system's default)", - Destination: &options.DNSDiscovery.Nameserver, - }, - &cli.BoolFlag{ - Name: "metrics-server", - Aliases: []string{"metrics"}, - Usage: "Enable the metrics server", - Destination: &options.Metrics.Enable, - }, - &cli.StringFlag{ - Name: "metrics-server-address", - Aliases: []string{"metrics-address"}, - Value: "127.0.0.1", - Usage: "Listening address of the metrics server", - Destination: &options.Metrics.Address, - }, - &cli.IntFlag{ - Name: "metrics-server-port", - Aliases: []string{"metrics-port"}, - Value: 8008, - Usage: "Listening HTTP port of the metrics server", - Destination: &options.Metrics.Port, - }, - &cli.BoolFlag{ - Name: "rpc", - Usage: "Enable the rpc server", - Destination: &options.RPCServer.Enable, - }, - &cli.IntFlag{ - Name: "rpc-port", - Value: 8545, - Usage: "Listening port of the rpc server", - Destination: &options.RPCServer.Port, - }, - &cli.StringFlag{ - Name: "rpc-address", - Value: "127.0.0.1", - Usage: "Listening address of the rpc server", - Destination: &options.RPCServer.Address, - }, - &cli.BoolFlag{ - Name: "rpc-admin", - Value: false, - Usage: "Enable access to JSON-RPC Admin API", - Destination: &options.RPCServer.Admin, - }, - &cli.BoolFlag{ - Name: "rpc-private", - Value: false, - Usage: "Enable access to JSON-RPC Private API", - Destination: &options.RPCServer.Private, - }, - - &cli.BoolFlag{ - Name: "rest", - Usage: "Enable Waku REST HTTP server", - Destination: &options.RESTServer.Enable, - }, - &cli.StringFlag{ - Name: "rest-address", - Value: "127.0.0.1", - Usage: "Listening address of the REST HTTP server", - Destination: &options.RESTServer.Address, - }, - &cli.IntFlag{ - Name: "rest-port", - Value: 8645, - Usage: "Listening port of the REST HTTP server", - Destination: &options.RESTServer.Port, - }, - &cli.IntFlag{ - Name: "rest-relay-cache-capacity", - Value: 30, - Usage: "Capacity of the Relay REST API message cache", - Destination: &options.RESTServer.RelayCacheCapacity, - }, - &cli.BoolFlag{ - Name: "rest-admin", - Value: false, - Usage: "Enable access to REST HTTP Admin API", - Destination: &options.RESTServer.Admin, - }, - &cli.BoolFlag{ - Name: "rest-private", - Value: false, - Usage: "Enable access to REST HTTP Private API", - Destination: &options.RESTServer.Private, - }, + cliFlags := []cli.Flag{ + &cli.IntFlag{ + Name: "tcp-port", + Aliases: []string{"port", "p"}, + Value: 60000, + Usage: "Libp2p TCP listening port (0 for random)", + Destination: &options.Port, }, + &cli.StringFlag{ + Name: "address", + Aliases: []string{"host", "listen-address"}, + Value: "0.0.0.0", + Usage: "Listening address", + Destination: &options.Address, + }, + &cli.BoolFlag{ + Name: "websocket-support", + Aliases: []string{"ws"}, + Usage: "Enable websockets support", + Destination: &options.Websocket.Enable, + }, + &cli.IntFlag{ + Name: "websocket-port", + Aliases: []string{"ws-port"}, + Value: 60001, + Usage: "Libp2p TCP listening port for websocket connection (0 for random)", + Destination: &options.Websocket.Port, + }, + &cli.StringFlag{ + Name: "websocket-address", + Aliases: []string{"ws-address"}, + Value: "0.0.0.0", + Usage: "Listening address for websocket connections", + Destination: &options.Websocket.Address, + }, + &cli.BoolFlag{ + Name: "websocket-secure-support", + Aliases: []string{"wss"}, + Usage: "Enable secure websockets support", + Destination: &options.Websocket.Secure, + }, + &cli.StringFlag{ + Name: "websocket-secure-key-path", + Aliases: []string{"wss-key"}, + Value: "/path/to/key.txt", + Usage: "Secure websocket key path", + Destination: &options.Websocket.KeyPath, + }, + &cli.StringFlag{ + Name: "websocket-secure-cert-path", + Aliases: []string{"wss-cert"}, + Value: "/path/to/cert.txt", + Usage: "Secure websocket certificate path", + Destination: &options.Websocket.CertPath, + }, + &cli.StringFlag{ + Name: "dns4-domain-name", + Value: "", + Usage: "The domain name resolving to the node's public IPv4 address", + Destination: &options.Dns4DomainName, + }, + &cli.StringFlag{ + Name: "nodekey", + Usage: "P2P node private key as hex. Can also be set with GOWAKU-NODEKEY env variable (default random)", + Destination: &options.NodeKey, + }, + &cli.StringFlag{ + Name: "key-file", + Value: "./nodekey", + Usage: "Path to a file containing the private key for the P2P node", + Destination: &options.KeyFile, + }, + &cli.StringFlag{ + Name: "key-password", + Value: "secret", + Usage: "Password used for the private key file", + Destination: &options.KeyPasswd, + }, + &cli.BoolFlag{ + Name: "generate-key", + Usage: "Generate private key file at path specified in --key-file with the password defined by --key-password", + Destination: &options.GenerateKey, + }, + &cli.BoolFlag{ + Name: "overwrite", + Usage: "When generating a keyfile, overwrite the nodekey file if it already exists", + Destination: &options.Overwrite, + }, + &cli.StringSliceFlag{ + Name: "staticnode", + Usage: "Multiaddr of peer to directly connect with. Option may be repeated", + Destination: &options.StaticNodes, + }, + &cli.IntFlag{ + Name: "keep-alive", + Value: 20, + Usage: "Interval in seconds for pinging peers to keep the connection alive.", + Destination: &options.KeepAlive, + }, + &cli.BoolFlag{ + Name: "use-db", + Aliases: []string{"sqlite-store"}, + Usage: "Use SQLiteDB to persist information", + Destination: &options.UseDB, + }, + &cli.BoolFlag{ + Name: "persist-messages", + Usage: "Enable message persistence", + Destination: &options.Store.PersistMessages, + Value: false, + }, + &cli.BoolFlag{ + Name: "persist-peers", + Usage: "Enable peer persistence", + Destination: &options.PersistPeers, + Value: false, + }, + &cli.StringFlag{ + Name: "nat", // This was added so js-waku test don't fail + Usage: "TODO: Not implemented yet. Specify method to use for determining public address: any, none ('any' will attempt upnp/pmp)", + Value: "any", + Destination: &options.NAT, // TODO: accept none,any,upnp,extaddr + }, + &cli.StringFlag{ + Name: "db-path", + Aliases: []string{"dbpath"}, + Value: "./store.db", + Usage: "Path to DB file", + Destination: &options.DBPath, + }, + &cli.StringFlag{ + Name: "advertise-address", + Usage: "External address to advertise to other nodes (overrides --address and --ws-address flags)", + Destination: &options.AdvertiseAddress, + }, + &cli.BoolFlag{ + Name: "show-addresses", + Usage: "Display listening addresses according to current configuration", + Destination: &options.ShowAddresses, + }, + &cli.StringFlag{ + Name: "log-level", + Aliases: []string{"l"}, + Value: "INFO", + Usage: "Define the logging level, supported strings are: DEBUG, INFO, WARN, ERROR, DPANIC, PANIC, FATAL, and their lower-case forms.", + Destination: &options.LogLevel, + }, + &cli.BoolFlag{ + Name: "version", + Value: false, + Usage: "prints the version", + Destination: &options.Version, + }, + &cli.StringFlag{ + Name: "log-encoding", + Value: "console", + Usage: "Define the encoding used for the logs: console, json", + Destination: &options.LogEncoding, + }, + &cli.BoolFlag{ + Name: "relay", + Value: true, + Usage: "Enable relay protocol", + Destination: &options.Relay.Enable, + }, + &cli.StringSliceFlag{ + Name: "topics", + Usage: "List of topics to listen", + Destination: &options.Relay.Topics, + }, + &cli.BoolFlag{ + Name: "relay-peer-exchange", + Aliases: []string{"peer-exchange"}, + Value: false, + Usage: "Enable GossipSub Peer Exchange", + Destination: &options.Relay.PeerExchange, + }, + &cli.IntFlag{ + Name: "min-relay-peers-to-publish", + Value: 1, + Usage: "Minimum number of peers to publish to Relay", + Destination: &options.Relay.MinRelayPeersToPublish, + }, + &cli.BoolFlag{ + Name: "store", + Usage: "Enable relay protocol", + Destination: &options.Store.Enable, + }, + &cli.BoolFlag{ + Name: "resume", + Usage: "Fix the gaps in message history", + Destination: &options.Store.ShouldResume, + }, + &cli.IntFlag{ + Name: "store-seconds", + Value: (86400 * 30), // 30 days + Usage: "maximum number of seconds before a message is removed from the store", + Destination: &options.Store.RetentionMaxSeconds, + }, + &cli.IntFlag{ + Name: "store-capacity", + Value: 50000, + Usage: "maximum number of messages to store", + Destination: &options.Store.RetentionMaxMessages, + }, + &cli.StringSliceFlag{ + Name: "storenode", + Usage: "Multiaddr of a peer that supports store protocol. Option may be repeated", + Destination: &options.Store.Nodes, + }, + &cli.BoolFlag{ + Name: "swap", + Usage: "Enable swap protocol", + Value: false, + Destination: &options.Swap.Enable, + }, + &cli.IntFlag{ + Name: "swap-mode", + Value: 0, + Usage: "Swap mode: 0=soft, 1=mock, 2=hard", + Destination: &options.Swap.Mode, + }, + &cli.IntFlag{ + Name: "swap-payment-threshold", + Value: 100, + Usage: "Threshold for payment", + Destination: &options.Swap.PaymentThreshold, + }, + &cli.IntFlag{ + Name: "swap-disconnect-threshold", + Value: -100, + Usage: "Threshold for disconnecting", + Destination: &options.Swap.DisconnectThreshold, + }, + &cli.BoolFlag{ + Name: "filter", + Usage: "Enable filter protocol", + Destination: &options.Filter.Enable, + }, + &cli.BoolFlag{ + Name: "light-client", + Usage: "Don't accept filter subscribers", + Destination: &options.Filter.DisableFullNode, + }, + &cli.StringSliceFlag{ + Name: "filternode", + Usage: "Multiaddr of a peer that supports filter protocol. Option may be repeated", + Destination: &options.Filter.Nodes, + }, + &cli.IntFlag{ + Name: "filter-timeout", + Value: 14400, + Usage: "Timeout for filter node in seconds", + Destination: &options.Filter.Timeout, + }, + &cli.BoolFlag{ + Name: "lightpush", + Usage: "Enable lightpush protocol", + Destination: &options.LightPush.Enable, + }, + &cli.StringSliceFlag{ + Name: "lightpushnode", + Usage: "Multiaddr of a peer that supports lightpush protocol. Option may be repeated", + Destination: &options.LightPush.Nodes, + }, + &cli.BoolFlag{ + Name: "discv5-discovery", + Usage: "Enable discovering nodes via Node Discovery v5", + Destination: &options.DiscV5.Enable, + }, + &cli.StringSliceFlag{ + Name: "discv5-bootstrap-node", + Usage: "Text-encoded ENR for bootstrap node. Used when connecting to the network. Option may be repeated", + Destination: &options.DiscV5.Nodes, + }, + &cli.IntFlag{ + Name: "discv5-udp-port", + Value: 9000, + Usage: "Listening UDP port for Node Discovery v5.", + Destination: &options.DiscV5.Port, + }, + &cli.BoolFlag{ + Name: "discv5-enr-auto-update", + Usage: "Discovery can automatically update its ENR with the IP address as seen by other nodes it communicates with.", + Destination: &options.DiscV5.AutoUpdate, + }, + &cli.BoolFlag{ + Name: "rendezvous", + Usage: "Enable rendezvous protocol for peer discovery", + Destination: &options.Rendezvous.Enable, + }, + &cli.StringSliceFlag{ + Name: "rendezvous-node", + Usage: "Multiaddr of a waku2 rendezvous node. Option may be repeated", + Destination: &options.Rendezvous.Nodes, + }, + &cli.BoolFlag{ + Name: "rendezvous-server", + Usage: "Node will act as rendezvous server", + Destination: &options.RendezvousServer.Enable, + }, + &cli.StringFlag{ + Name: "rendezvous-db-path", + Value: "/tmp/rendezvous", + Usage: "Path where peer records database will be stored", + Destination: &options.RendezvousServer.DBPath, + }, + &cli.BoolFlag{ + Name: "dns-discovery", + Usage: "Enable DNS discovery", + Destination: &options.DNSDiscovery.Enable, + }, + &cli.StringFlag{ + Name: "dns-discovery-url", + Usage: "URL for DNS node list in format 'enrtree://@'", + Destination: &options.DNSDiscovery.URL, + }, + &cli.StringFlag{ + Name: "dns-discovery-name-server", + Aliases: []string{"dns-discovery-nameserver"}, + Usage: "DNS nameserver IP to query (empty to use system's default)", + Destination: &options.DNSDiscovery.Nameserver, + }, + &cli.BoolFlag{ + Name: "metrics-server", + Aliases: []string{"metrics"}, + Usage: "Enable the metrics server", + Destination: &options.Metrics.Enable, + }, + &cli.StringFlag{ + Name: "metrics-server-address", + Aliases: []string{"metrics-address"}, + Value: "127.0.0.1", + Usage: "Listening address of the metrics server", + Destination: &options.Metrics.Address, + }, + &cli.IntFlag{ + Name: "metrics-server-port", + Aliases: []string{"metrics-port"}, + Value: 8008, + Usage: "Listening HTTP port of the metrics server", + Destination: &options.Metrics.Port, + }, + &cli.BoolFlag{ + Name: "rpc", + Usage: "Enable the rpc server", + Destination: &options.RPCServer.Enable, + }, + &cli.IntFlag{ + Name: "rpc-port", + Value: 8545, + Usage: "Listening port of the rpc server", + Destination: &options.RPCServer.Port, + }, + &cli.StringFlag{ + Name: "rpc-address", + Value: "127.0.0.1", + Usage: "Listening address of the rpc server", + Destination: &options.RPCServer.Address, + }, + &cli.BoolFlag{ + Name: "rpc-admin", + Value: false, + Usage: "Enable access to JSON-RPC Admin API", + Destination: &options.RPCServer.Admin, + }, + &cli.BoolFlag{ + Name: "rpc-private", + Value: false, + Usage: "Enable access to JSON-RPC Private API", + Destination: &options.RPCServer.Private, + }, + + &cli.BoolFlag{ + Name: "rest", + Usage: "Enable Waku REST HTTP server", + Destination: &options.RESTServer.Enable, + }, + &cli.StringFlag{ + Name: "rest-address", + Value: "127.0.0.1", + Usage: "Listening address of the REST HTTP server", + Destination: &options.RESTServer.Address, + }, + &cli.IntFlag{ + Name: "rest-port", + Value: 8645, + Usage: "Listening port of the REST HTTP server", + Destination: &options.RESTServer.Port, + }, + &cli.IntFlag{ + Name: "rest-relay-cache-capacity", + Value: 30, + Usage: "Capacity of the Relay REST API message cache", + Destination: &options.RESTServer.RelayCacheCapacity, + }, + &cli.BoolFlag{ + Name: "rest-admin", + Value: false, + Usage: "Enable access to REST HTTP Admin API", + Destination: &options.RESTServer.Admin, + }, + &cli.BoolFlag{ + Name: "rest-private", + Value: false, + Usage: "Enable access to REST HTTP Private API", + Destination: &options.RESTServer.Private, + }, + } + + rlnFlags := rlnFlags() + cliFlags = append(cliFlags, rlnFlags...) + + app := &cli.App{ + Flags: cliFlags, Action: func(c *cli.Context) error { // for go-libp2p loggers lvl, err := logging.LevelFromString(options.LogLevel) diff --git a/waku/node.go b/waku/node.go index bdb1a093..48831520 100644 --- a/waku/node.go +++ b/waku/node.go @@ -19,7 +19,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/enode" dssql "github.com/ipfs/go-ds-sql" - "github.com/status-im/go-rln/rln" "github.com/urfave/cli/v2" "go.uber.org/zap" @@ -256,41 +255,7 @@ func Execute(options Options) { nodeOpts = append(nodeOpts, node.WithDiscoveryV5(options.DiscV5.Port, bootnodes, options.DiscV5.AutoUpdate, pubsub.WithDiscoveryOpts(discovery.Limit(45), discovery.TTL(time.Duration(20)*time.Second)))) } - loadedCredentialsFromFile := false - if options.RLNRelay.Enable { - if !options.Relay.Enable { - failOnErr(errors.New("relay not available"), "Could not enable RLN Relay") - } - - if !options.RLNRelay.Dynamic { - nodeOpts = append(nodeOpts, node.WithStaticRLNRelay(options.RLNRelay.PubsubTopic, options.RLNRelay.ContentTopic, rln.MembershipIndex(options.RLNRelay.MembershipIndex), nil)) - } else { - - var ethPrivKey *ecdsa.PrivateKey - if options.RLNRelay.ETHPrivateKey != "" { - k, err := crypto.ToECDSA(common.FromHex(options.RLNRelay.ETHPrivateKey)) - failOnErr(err, "Invalid private key") - ethPrivKey = k - } - - loaded, idKey, idCommitment, membershipIndex, err := getMembershipCredentials(options) - failOnErr(err, "Invalid membership credentials") - - loadedCredentialsFromFile = loaded - - nodeOpts = append(nodeOpts, node.WithDynamicRLNRelay( - options.RLNRelay.PubsubTopic, - options.RLNRelay.ContentTopic, - membershipIndex, - idKey, - idCommitment, - nil, - options.RLNRelay.ETHClientAddress, - ethPrivKey, - common.HexToAddress(options.RLNRelay.MembershipContractAddress), - )) - } - } + checkForRLN(options, &nodeOpts) wakuNode, err := node.New(ctx, nodeOpts...) @@ -348,10 +313,7 @@ func Execute(options Options) { } } - if options.RLNRelay.Enable && options.RLNRelay.Dynamic && !loadedCredentialsFromFile { - err := writeRLNMembershipCredentialsToFile(wakuNode.RLNRelay().MembershipKeyPair(), wakuNode.RLNRelay().MembershipIndex(), options.RLNRelay.CredentialsFile, []byte(options.KeyPasswd), options.Overwrite) - failOnErr(err, "Could not write membership credentials file") - } + onStartRLN(wakuNode, options) var rpcServer *rpc.WakuRpc if options.RPCServer.Enable { diff --git a/waku/node_no_rln.go b/waku/node_no_rln.go new file mode 100644 index 00000000..0651f702 --- /dev/null +++ b/waku/node_no_rln.go @@ -0,0 +1,14 @@ +//go:build !gowaku_rln +// +build !gowaku_rln + +package waku + +import "github.com/status-im/go-waku/waku/v2/node" + +func checkForRLN(options Options, nodeOpts *[]node.WakuNodeOption) { + // Do nothing +} + +func onStartRLN(wakuNode *node.WakuNode, options Options) { + // Do nothing +} diff --git a/waku/node_rln.go b/waku/node_rln.go new file mode 100644 index 00000000..e95ad31e --- /dev/null +++ b/waku/node_rln.go @@ -0,0 +1,58 @@ +//go:build gowaku_rln +// +build gowaku_rln + +package waku + +import ( + "crypto/ecdsa" + "errors" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/status-im/go-rln/rln" + "github.com/status-im/go-waku/waku/v2/node" +) + +var loadedCredentialsFromFile bool = false + +func checkForRLN(options Options, nodeOpts *[]node.WakuNodeOption) { + if options.RLNRelay.Enable { + if !options.Relay.Enable { + failOnErr(errors.New("relay not available"), "Could not enable RLN Relay") + } + if !options.RLNRelay.Dynamic { + *nodeOpts = append(*nodeOpts, node.WithStaticRLNRelay(options.RLNRelay.PubsubTopic, options.RLNRelay.ContentTopic, rln.MembershipIndex(options.RLNRelay.MembershipIndex), nil)) + } else { + + var ethPrivKey *ecdsa.PrivateKey + if options.RLNRelay.ETHPrivateKey != "" { + k, err := crypto.ToECDSA(common.FromHex(options.RLNRelay.ETHPrivateKey)) + failOnErr(err, "Invalid private key") + ethPrivKey = k + } + + loaded, idKey, idCommitment, membershipIndex, err := getMembershipCredentials(options) + failOnErr(err, "Invalid membership credentials") + + loadedCredentialsFromFile = loaded + + *nodeOpts = append(*nodeOpts, node.WithDynamicRLNRelay( + options.RLNRelay.PubsubTopic, + options.RLNRelay.ContentTopic, + membershipIndex, + idKey, + idCommitment, + nil, + options.RLNRelay.ETHClientAddress, + ethPrivKey, + common.HexToAddress(options.RLNRelay.MembershipContractAddress), + )) + } + } +} + +func onStartRLN(wakuNode *node.WakuNode, options Options) { + if options.RLNRelay.Enable && options.RLNRelay.Dynamic && !loadedCredentialsFromFile { + err := writeRLNMembershipCredentialsToFile(wakuNode.RLNRelay().MembershipKeyPair(), wakuNode.RLNRelay().MembershipIndex(), options.RLNRelay.CredentialsFile, []byte(options.KeyPasswd), options.Overwrite) + failOnErr(err, "Could not write membership credentials file") + } +} diff --git a/waku/rln-credentials.go b/waku/rln-credentials.go index 0068fc29..62d53d0d 100644 --- a/waku/rln-credentials.go +++ b/waku/rln-credentials.go @@ -1,3 +1,6 @@ +//go:build gowaku_rln +// +build gowaku_rln + package waku import ( diff --git a/waku/v2/node/wakunode2.go b/waku/v2/node/wakunode2.go index 0e755d44..03709035 100644 --- a/waku/v2/node/wakunode2.go +++ b/waku/v2/node/wakunode2.go @@ -2,7 +2,6 @@ package node import ( "context" - "encoding/hex" "errors" "fmt" "net" @@ -24,7 +23,6 @@ import ( ma "github.com/multiformats/go-multiaddr" "go.opencensus.io/stats" - r "github.com/status-im/go-rln/rln" rendezvous "github.com/status-im/go-waku-rendezvous" "github.com/status-im/go-waku/logging" "github.com/status-im/go-waku/waku/try" @@ -35,7 +33,6 @@ import ( "github.com/status-im/go-waku/waku/v2/protocol/lightpush" "github.com/status-im/go-waku/waku/v2/protocol/pb" "github.com/status-im/go-waku/waku/v2/protocol/relay" - "github.com/status-im/go-waku/waku/v2/protocol/rln" "github.com/status-im/go-waku/waku/v2/protocol/store" "github.com/status-im/go-waku/waku/v2/protocol/swap" @@ -51,6 +48,17 @@ type Peer struct { type storeFactory func(w *WakuNode) store.Store +type MembershipKeyPair = struct { + IDKey [32]byte + IDCommitment [32]byte +} + +type RLNRelay interface { + MembershipKeyPair() MembershipKeyPair + MembershipIndex() uint + AppendRLNProof(msg *pb.WakuMessage, senderEpochTime time.Time) error +} + type WakuNode struct { host host.Host opts *WakuNodeParameters @@ -62,7 +70,7 @@ type WakuNode struct { rendezvous *rendezvous.RendezvousService store store.Store swap *swap.WakuSwap - rlnRelay *rln.WakuRLNRelay + rlnRelay RLNRelay wakuFlag utils.WakuEnrBitfield localNode *enode.LocalNode @@ -391,11 +399,6 @@ func (w *WakuNode) Relay() *relay.WakuRelay { return w.relay } -// RLNRelay is used to access any operation related to Waku RLN protocol -func (w *WakuNode) RLNRelay() *rln.WakuRLNRelay { - return w.rlnRelay -} - // Store is used to access any operation related to Waku Store protocol func (w *WakuNode) Store() store.Store { return w.store @@ -661,78 +664,3 @@ func (w *WakuNode) Peers() ([]*Peer, error) { } return peers, nil } - -func (w *WakuNode) mountRlnRelay() error { - // check whether inputs are provided - // relay protocol is the prerequisite of rln-relay - if w.Relay() == nil { - return errors.New("relay protocol is required") - } - - // check whether the pubsub topic is supported at the relay level - topicFound := false - for _, t := range w.Relay().Topics() { - if t == w.opts.rlnRelayPubsubTopic { - topicFound = true - break - } - } - - if !topicFound { - return errors.New("relay protocol does not support the configured pubsub topic") - } - - if !w.opts.rlnRelayDynamic { - w.log.Info("setting up waku-rln-relay in off-chain mode") - // set up rln relay inputs - groupKeys, memKeyPair, memIndex, err := rln.StaticSetup(w.opts.rlnRelayMemIndex) - if err != nil { - return err - } - - // mount rlnrelay in off-chain mode with a static group of users - w.rlnRelay, err = rln.RlnRelayStatic(w.ctx, w.relay, groupKeys, memKeyPair, memIndex, w.opts.rlnRelayPubsubTopic, w.opts.rlnRelayContentTopic, w.opts.rlnSpamHandler, w.log) - if err != nil { - return err - } - - w.log.Info("membership id key", zap.String("IDKey", hex.EncodeToString(memKeyPair.IDKey[:]))) - w.log.Info("membership id commitment key", zap.String("IDCommitment", hex.EncodeToString(memKeyPair.IDCommitment[:]))) - - // check the correct construction of the tree by comparing the calculated root against the expected root - // no error should happen as it is already captured in the unit tests - root, err := w.rlnRelay.RLN.GetMerkleRoot() - if err != nil { - return err - } - - expectedRoot := r.STATIC_GROUP_MERKLE_ROOT - if hex.EncodeToString(root[:]) != expectedRoot { - return errors.New("root mismatch: something went wrong not in Merkle tree construction") - } - - w.log.Info("the calculated root", zap.String("root", hex.EncodeToString(root[:]))) - } else { - w.log.Info("setting up waku-rln-relay in on-chain mode") - - // check if the peer has provided its rln credentials - var memKeyPair *r.MembershipKeyPair - if w.opts.rlnRelayIDCommitment != nil && w.opts.rlnRelayIDKey != nil { - memKeyPair = &r.MembershipKeyPair{ - IDCommitment: *w.opts.rlnRelayIDCommitment, - IDKey: *w.opts.rlnRelayIDKey, - } - } - - // mount the rln relay protocol in the on-chain/dynamic mode - var err error - w.rlnRelay, err = rln.RlnRelayDynamic(context.Background(), w.relay, w.opts.rlnETHClientAddress, w.opts.rlnETHPrivateKey, w.opts.rlnMembershipContractAddress, memKeyPair, w.opts.rlnRelayMemIndex, w.opts.rlnRelayPubsubTopic, w.opts.rlnRelayContentTopic, w.opts.rlnSpamHandler, w.log) - if err != nil { - return err - } - } - - w.log.Info("mounted waku RLN relay", zap.String("pubsubTopic", w.opts.rlnRelayPubsubTopic), zap.String("contentTopic", w.opts.rlnRelayContentTopic)) - - return nil -} diff --git a/waku/v2/node/wakunode2_no_rln.go b/waku/v2/node/wakunode2_no_rln.go new file mode 100644 index 00000000..6b798f73 --- /dev/null +++ b/waku/v2/node/wakunode2_no_rln.go @@ -0,0 +1,13 @@ +//go:build !gowaku_rln +// +build !gowaku_rln + +package node + +// RLNRelay is used to access any operation related to Waku RLN protocol +func (w *WakuNode) RLNRelay() RLNRelay { + return nil +} + +func (w *WakuNode) mountRlnRelay() error { + return nil +} diff --git a/waku/v2/node/wakunode2_rln.go b/waku/v2/node/wakunode2_rln.go new file mode 100644 index 00000000..745e7349 --- /dev/null +++ b/waku/v2/node/wakunode2_rln.go @@ -0,0 +1,96 @@ +//go:build gowaku_rln +// +build gowaku_rln + +package node + +import ( + "context" + "encoding/hex" + "errors" + + r "github.com/status-im/go-rln/rln" + "github.com/status-im/go-waku/waku/v2/protocol/rln" + "go.uber.org/zap" +) + +// RLNRelay is used to access any operation related to Waku RLN protocol +func (w *WakuNode) RLNRelay() RLNRelay { + return w.rlnRelay +} + +func (w *WakuNode) mountRlnRelay() error { + // check whether inputs are provided + // relay protocol is the prerequisite of rln-relay + if w.Relay() == nil { + return errors.New("relay protocol is required") + } + + // check whether the pubsub topic is supported at the relay level + topicFound := false + for _, t := range w.Relay().Topics() { + if t == w.opts.rlnRelayPubsubTopic { + topicFound = true + break + } + } + + if !topicFound { + return errors.New("relay protocol does not support the configured pubsub topic") + } + + if !w.opts.rlnRelayDynamic { + w.log.Info("setting up waku-rln-relay in off-chain mode") + // set up rln relay inputs + groupKeys, memKeyPair, memIndex, err := rln.StaticSetup(w.opts.rlnRelayMemIndex) + if err != nil { + return err + } + + // mount rlnrelay in off-chain mode with a static group of users + rlnRelay, err := rln.RlnRelayStatic(w.ctx, w.relay, groupKeys, memKeyPair, memIndex, w.opts.rlnRelayPubsubTopic, w.opts.rlnRelayContentTopic, w.opts.rlnSpamHandler, w.log) + if err != nil { + return err + } + + w.rlnRelay = rlnRelay + + w.log.Info("membership id key", zap.String("IDKey", hex.EncodeToString(memKeyPair.IDKey[:]))) + w.log.Info("membership id commitment key", zap.String("IDCommitment", hex.EncodeToString(memKeyPair.IDCommitment[:]))) + + // check the correct construction of the tree by comparing the calculated root against the expected root + // no error should happen as it is already captured in the unit tests + root, err := rlnRelay.RLN.GetMerkleRoot() + if err != nil { + return err + } + + expectedRoot := r.STATIC_GROUP_MERKLE_ROOT + if hex.EncodeToString(root[:]) != expectedRoot { + return errors.New("root mismatch: something went wrong not in Merkle tree construction") + } + + w.log.Info("the calculated root", zap.String("root", hex.EncodeToString(root[:]))) + } else { + w.log.Info("setting up waku-rln-relay in on-chain mode") + + // check if the peer has provided its rln credentials + var memKeyPair *r.MembershipKeyPair + if w.opts.rlnRelayIDCommitment != nil && w.opts.rlnRelayIDKey != nil { + memKeyPair = &r.MembershipKeyPair{ + IDCommitment: *w.opts.rlnRelayIDCommitment, + IDKey: *w.opts.rlnRelayIDKey, + } + } + + // mount the rln relay protocol in the on-chain/dynamic mode + var err error + w.rlnRelay, err = rln.RlnRelayDynamic(context.Background(), w.relay, w.opts.rlnETHClientAddress, w.opts.rlnETHPrivateKey, w.opts.rlnMembershipContractAddress, memKeyPair, w.opts.rlnRelayMemIndex, w.opts.rlnRelayPubsubTopic, w.opts.rlnRelayContentTopic, w.opts.rlnSpamHandler, w.log) + if err != nil { + return err + } + } + + w.log.Info("mounted waku RLN relay", zap.String("pubsubTopic", w.opts.rlnRelayPubsubTopic), zap.String("contentTopic", w.opts.rlnRelayContentTopic)) + + return nil +} diff --git a/waku/v2/node/wakuoptions.go b/waku/v2/node/wakuoptions.go index 63c74dcb..da471ebc 100644 --- a/waku/v2/node/wakuoptions.go +++ b/waku/v2/node/wakuoptions.go @@ -22,10 +22,9 @@ import ( "github.com/libp2p/go-libp2p/p2p/transport/tcp" "github.com/multiformats/go-multiaddr" manet "github.com/multiformats/go-multiaddr/net" - r "github.com/status-im/go-rln/rln" rendezvous "github.com/status-im/go-waku-rendezvous" "github.com/status-im/go-waku/waku/v2/protocol/filter" - "github.com/status-im/go-waku/waku/v2/protocol/rln" + "github.com/status-im/go-waku/waku/v2/protocol/pb" "github.com/status-im/go-waku/waku/v2/protocol/store" "github.com/status-im/go-waku/waku/v2/utils" "go.uber.org/zap" @@ -84,13 +83,13 @@ type WakuNodeParameters struct { discV5autoUpdate bool enableRLN bool - rlnRelayMemIndex r.MembershipIndex + rlnRelayMemIndex uint rlnRelayPubsubTopic string rlnRelayContentTopic string rlnRelayDynamic bool - rlnSpamHandler rln.SpamHandler - rlnRelayIDKey *r.IDKey - rlnRelayIDCommitment *r.IDCommitment + rlnSpamHandler func(message *pb.WakuMessage) error + rlnRelayIDKey *[32]byte + rlnRelayIDCommitment *[32]byte rlnETHPrivateKey *ecdsa.PrivateKey rlnETHClientAddress string rlnMembershipContractAddress common.Address @@ -420,35 +419,6 @@ func WithSecureWebsockets(address string, port int, certPath string, keyPath str } } -func WithStaticRLNRelay(pubsubTopic string, contentTopic string, memberIndex r.MembershipIndex, spamHandler rln.SpamHandler) WakuNodeOption { - return func(params *WakuNodeParameters) error { - params.enableRLN = true - params.rlnRelayDynamic = false - params.rlnRelayMemIndex = memberIndex - params.rlnRelayPubsubTopic = pubsubTopic - params.rlnRelayContentTopic = contentTopic - params.rlnSpamHandler = spamHandler - return nil - } -} - -func WithDynamicRLNRelay(pubsubTopic string, contentTopic string, memberIndex r.MembershipIndex, idKey *r.IDKey, idCommitment *r.IDCommitment, spamHandler rln.SpamHandler, ethClientAddress string, ethPrivateKey *ecdsa.PrivateKey, membershipContractAddress common.Address) WakuNodeOption { - return func(params *WakuNodeParameters) error { - params.enableRLN = true - params.rlnRelayDynamic = true - params.rlnRelayMemIndex = memberIndex - params.rlnRelayIDKey = idKey - params.rlnRelayIDCommitment = idCommitment - params.rlnRelayPubsubTopic = pubsubTopic - params.rlnRelayContentTopic = contentTopic - params.rlnSpamHandler = spamHandler - params.rlnETHClientAddress = ethClientAddress - params.rlnETHPrivateKey = ethPrivateKey - params.rlnMembershipContractAddress = membershipContractAddress - return nil - } -} - // Default options used in the libp2p node var DefaultLibP2POptions = []libp2p.Option{ libp2p.ChainOptions( diff --git a/waku/v2/node/wakuoptions_rln.go b/waku/v2/node/wakuoptions_rln.go new file mode 100644 index 00000000..307a5754 --- /dev/null +++ b/waku/v2/node/wakuoptions_rln.go @@ -0,0 +1,41 @@ +//go:build gowaku_rln +// +build gowaku_rln + +package node + +import ( + "crypto/ecdsa" + + "github.com/ethereum/go-ethereum/common" + r "github.com/status-im/go-rln/rln" + "github.com/status-im/go-waku/waku/v2/protocol/rln" +) + +func WithStaticRLNRelay(pubsubTopic string, contentTopic string, memberIndex r.MembershipIndex, spamHandler rln.SpamHandler) WakuNodeOption { + return func(params *WakuNodeParameters) error { + params.enableRLN = true + params.rlnRelayDynamic = false + params.rlnRelayMemIndex = memberIndex + params.rlnRelayPubsubTopic = pubsubTopic + params.rlnRelayContentTopic = contentTopic + params.rlnSpamHandler = spamHandler + return nil + } +} + +func WithDynamicRLNRelay(pubsubTopic string, contentTopic string, memberIndex r.MembershipIndex, idKey *r.IDKey, idCommitment *r.IDCommitment, spamHandler rln.SpamHandler, ethClientAddress string, ethPrivateKey *ecdsa.PrivateKey, membershipContractAddress common.Address) WakuNodeOption { + return func(params *WakuNodeParameters) error { + params.enableRLN = true + params.rlnRelayDynamic = true + params.rlnRelayMemIndex = memberIndex + params.rlnRelayIDKey = idKey + params.rlnRelayIDCommitment = idCommitment + params.rlnRelayPubsubTopic = pubsubTopic + params.rlnRelayContentTopic = contentTopic + params.rlnSpamHandler = spamHandler + params.rlnETHClientAddress = ethClientAddress + params.rlnETHPrivateKey = ethPrivateKey + params.rlnMembershipContractAddress = membershipContractAddress + return nil + } +} diff --git a/waku/v2/protocol/rln/rln_relay_test.go b/waku/v2/protocol/rln/rln_relay_test.go index b8f865c1..58c11bbb 100644 --- a/waku/v2/protocol/rln/rln_relay_test.go +++ b/waku/v2/protocol/rln/rln_relay_test.go @@ -100,7 +100,7 @@ func (s *WakuRLNRelaySuite) TestUpdateLogAndHasDuplicate() { s.Require().False(result1) // No duplicate is found // Add it to the log - added, err := rlnRelay.UpdateLog(wm1) + added, err := rlnRelay.updateLog(wm1) s.Require().NoError(err) s.Require().True(added) @@ -110,7 +110,7 @@ func (s *WakuRLNRelaySuite) TestUpdateLogAndHasDuplicate() { s.Require().False(result2) // No duplicate is found // Add it to the log - added, err = rlnRelay.UpdateLog(wm2) + added, err = rlnRelay.updateLog(wm2) s.Require().NoError(err) s.Require().True(added) diff --git a/waku/v2/protocol/rln/waku_rln_relay.go b/waku/v2/protocol/rln/waku_rln_relay.go index 1bb30a22..7a8fc14f 100644 --- a/waku/v2/protocol/rln/waku_rln_relay.go +++ b/waku/v2/protocol/rln/waku_rln_relay.go @@ -125,7 +125,7 @@ func (rln *WakuRLNRelay) HasDuplicate(msg *pb.WakuMessage) (bool, error) { return matched, nil } -func (rln *WakuRLNRelay) UpdateLog(msg *pb.WakuMessage) (bool, error) { +func (rln *WakuRLNRelay) updateLog(msg *pb.WakuMessage) (bool, error) { // extracts the `ProofMetadata` of the supplied messages `msg` and // saves it in the `nullifierLog` of the `rlnPeer` @@ -225,7 +225,7 @@ func (rln *WakuRLNRelay) ValidateMessage(msg *pb.WakuMessage, optionalTime *time // insert the message to the log // the result of `updateLog` is discarded because message insertion is guaranteed by the implementation i.e., // it will never error out - _, err = rln.UpdateLog(msg) + _, err = rln.updateLog(msg) if err != nil { return MessageValidationResult_Unknown, err } @@ -270,7 +270,7 @@ func (r *WakuRLNRelay) MembershipIndex() r.MembershipIndex { return r.membershipIndex } -type SpamHandler func(message *pb.WakuMessage) error +type SpamHandler = func(message *pb.WakuMessage) error // this function sets a validator for the waku messages published on the supplied pubsubTopic and contentTopic // if contentTopic is empty, then validation takes place for All the messages published on the given pubsubTopic diff --git a/waku_no_rln.go b/waku_no_rln.go new file mode 100644 index 00000000..1fa9f58a --- /dev/null +++ b/waku_no_rln.go @@ -0,0 +1,10 @@ +//go:build !gowaku_rln +// +build !gowaku_rln + +package main + +import "github.com/urfave/cli/v2" + +func rlnFlags() []cli.Flag { + return nil +} diff --git a/waku_rln.go b/waku_rln.go new file mode 100644 index 00000000..5f4de8e1 --- /dev/null +++ b/waku_rln.go @@ -0,0 +1,74 @@ +//go:build gowaku_rln +// +build gowaku_rln + +package main + +import "github.com/urfave/cli/v2" + +func rlnFlags() []cli.Flag { + return []cli.Flag{ + &cli.BoolFlag{ + Name: "rln-relay", + Value: false, + Usage: "Enable spam protection through rln-relay", + Destination: &options.RLNRelay.Enable, + }, + &cli.IntFlag{ + Name: "rln-relay-membership-index", + Value: 0, + Usage: "(experimental) the index of node in the rln-relay group: a value between 0-99 inclusive", + Destination: &options.RLNRelay.MembershipIndex, + }, + &cli.StringFlag{ + Name: "rln-relay-pubsub-topic", + Value: "/waku/2/default-waku/proto", + Usage: "the pubsub topic for which rln-relay gets enabled", + Destination: &options.RLNRelay.PubsubTopic, + }, + &cli.StringFlag{ + Name: "rln-relay-content-topic", + Value: "/toy-chat/2/luzhou/proto", + Usage: "the content topic for which rln-relay gets enabled", + Destination: &options.RLNRelay.ContentTopic, + }, + &cli.BoolFlag{ + Name: "rln-relay-dynamic", + Usage: "Enable waku-rln-relay with on-chain dynamic group management", + Destination: &options.RLNRelay.Dynamic, + }, + &cli.StringFlag{ + Name: "rln-relay-id", + Usage: "Rln relay identity secret key as a Hex string", + Destination: &options.RLNRelay.IDKey, + }, + &cli.StringFlag{ + Name: "rln-relay-id-commitment", + Usage: "Rln relay identity commitment key as a Hex string", + Destination: &options.RLNRelay.IDCommitment, + }, + &cli.StringFlag{ + Name: "rln-relay-membership-credentials-file", + Usage: "RLN relay membership credentials file", + Value: "rlnCredentials.txt", + Destination: &options.RLNRelay.CredentialsFile, + }, + // TODO: this is a good candidate option for subcommands + // TODO: consider accepting a private key file and passwd + &cli.StringFlag{ + Name: "eth-private-key", + Usage: "Ethereum Goerli testnet account private key used for registering in member contract", + Destination: &options.RLNRelay.ETHPrivateKey, + }, + &cli.StringFlag{ + Name: "eth-client-address", + Usage: "Ethereum testnet client address", + Value: "ws://localhost:8545", + Destination: &options.RLNRelay.ETHClientAddress, + }, + &cli.StringFlag{ + Name: "eth-mem-contract-address", + Usage: "Address of membership contract on an Ethereum testnet", + Destination: &options.RLNRelay.MembershipContractAddress, + }, + } +}