fix: chat2 feedback

This commit is contained in:
Richard Ramos 2022-09-11 17:08:58 -04:00
parent db85642862
commit 3716ebdf1d
No known key found for this signature in database
GPG Key ID: BD36D48BC9FFC88C
18 changed files with 79 additions and 33 deletions

View File

@ -240,6 +240,9 @@ func (c *Chat) SendMessage(line string) {
err := c.publish(tCtx, line)
if err != nil {
if err.Error() == "validation failed" {
err = errors.New("message rate violation!")
}
c.ui.ErrorMessage(err)
}
}

View File

@ -6,6 +6,7 @@ import (
"net"
tea "github.com/charmbracelet/bubbletea"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/multiformats/go-multiaddr"
"github.com/status-im/go-waku/waku/v2/node"
@ -42,8 +43,12 @@ func execute(options Options) {
return nil
}
registrationHandler := func(tx *types.Transaction) {
fmt.Println(fmt.Sprintf("You are registered to the rln membership contract, find details of your registration transaction in https://goerli.etherscan.io/tx/%s", tx.Hash()))
}
if options.RLNRelay.Dynamic {
idKey, idCommitment, index, err := getMembershipCredentials(options.RLNRelay.CredentialsFile, options.RLNRelay.IDKey, options.RLNRelay.IDCommitment, options.RLNRelay.MembershipIndex)
idKey, idCommitment, index, err := getMembershipCredentials(options.RLNRelay.CredentialsPath, options.RLNRelay.IDKey, options.RLNRelay.IDCommitment, options.RLNRelay.MembershipIndex)
if err != nil {
fmt.Println(err)
return
@ -60,6 +65,7 @@ func execute(options Options) {
options.RLNRelay.ETHClientAddress,
options.RLNRelay.ETHPrivateKey,
options.RLNRelay.MembershipContractAddress,
registrationHandler,
))
} else {
opts = append(opts, node.WithStaticRLNRelay(
@ -113,7 +119,7 @@ func execute(options Options) {
if options.RLNRelay.Enable && options.RLNRelay.Dynamic {
if options.RLNRelay.IDKey == "" && options.RLNRelay.IDCommitment == "" {
// Write membership credentials file only if the idkey and commitment are not specified
err := writeRLNMembershipCredentialsToFile(options.RLNRelay.CredentialsFile, wakuNode.RLNRelay().MembershipKeyPair(), wakuNode.RLNRelay().MembershipIndex())
err := writeRLNMembershipCredentialsToFile(options.RLNRelay.CredentialsPath, wakuNode.RLNRelay().MembershipKeyPair(), wakuNode.RLNRelay().MembershipIndex())
if err != nil {
fmt.Println(err.Error())
return

View File

@ -214,10 +214,10 @@ func getFlags() []cli.Flag {
Destination: &options.RLNRelay.IDCommitment,
},
&cli.PathFlag{
Name: "rln-relay-membership-credentials-file",
Usage: "RLN relay membership credentials file",
Value: "rlnCredentials.txt",
Destination: &options.RLNRelay.CredentialsFile,
Name: "rln-relay-cred-path",
Usage: "The path for persisting rln-relay credential",
Value: "",
Destination: &options.RLNRelay.CredentialsPath,
},
// TODO: this is a good candidate option for subcommands
// TODO: consider accepting a private key file and passwd

View File

@ -29,7 +29,7 @@ type RelayOptions struct {
type RLNRelayOptions struct {
Enable bool
CredentialsFile string
CredentialsPath string
MembershipIndex int
PubsubTopic string
ContentTopic string

View File

@ -6,6 +6,7 @@ import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/ethereum/go-ethereum/common"
"github.com/status-im/go-rln/rln"
@ -21,6 +22,8 @@ type membershipCredentials struct {
Index rln.MembershipIndex `json:"rlnIndex"`
}
const RLN_CREDENTIALS_FILENAME = "rlnCredentials.txt"
func fileExists(path string) bool {
if _, err := os.Stat(path); err == nil {
return false
@ -34,6 +37,8 @@ func fileExists(path string) bool {
}
func writeRLNMembershipCredentialsToFile(path string, keyPair rln.MembershipKeyPair, idx rln.MembershipIndex) error {
path = filepath.Join(path, RLN_CREDENTIALS_FILENAME)
if fileExists(path) {
return nil
}
@ -49,8 +54,8 @@ func writeRLNMembershipCredentialsToFile(path string, keyPair rln.MembershipKeyP
return ioutil.WriteFile(path, credentialsJSON, 0600)
}
func loadMembershipCredentialsFromFile(path string) (rln.MembershipKeyPair, rln.MembershipIndex, error) {
src, err := ioutil.ReadFile(path)
func loadMembershipCredentialsFromFile(rlnCredentialsPath string) (rln.MembershipKeyPair, rln.MembershipIndex, error) {
src, err := ioutil.ReadFile(rlnCredentialsPath)
if err != nil {
return rln.MembershipKeyPair{}, rln.MembershipIndex(0), err
}
@ -72,6 +77,7 @@ func getMembershipCredentials(path string, rlnIDKey string, rlnIDCommitment stri
var osErr error
if !valuesWereInput {
path = filepath.Join(path, RLN_CREDENTIALS_FILENAME)
if _, osErr = os.Stat(path); osErr == nil {
if keyPair, index, err := loadMembershipCredentialsFromFile(path); err != nil {
return nil, nil, rln.MembershipIndex(0), fmt.Errorf("could not read membership credentials file: %w", err)

View File

@ -263,7 +263,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))))
}
checkForRLN(options, &nodeOpts)
checkForRLN(logger, options, &nodeOpts)
wakuNode, err := node.New(ctx, nodeOpts...)

View File

@ -3,9 +3,12 @@
package waku
import "github.com/status-im/go-waku/waku/v2/node"
import (
"github.com/status-im/go-waku/waku/v2/node"
"go.uber.org/zap"
)
func checkForRLN(options Options, nodeOpts *[]node.WakuNodeOption) {
func checkForRLN(logger *zap.Logger, options Options, nodeOpts *[]node.WakuNodeOption) {
// Do nothing
}

View File

@ -6,13 +6,15 @@ package waku
import (
"crypto/ecdsa"
"errors"
"github.com/status-im/go-rln/rln"
"github.com/status-im/go-waku/waku/v2/node"
"go.uber.org/zap"
)
var loadedCredentialsFromFile bool = false
func checkForRLN(options Options, nodeOpts *[]node.WakuNodeOption) {
func checkForRLN(logger *zap.Logger, options Options, nodeOpts *[]node.WakuNodeOption) {
if options.RLNRelay.Enable {
if !options.Relay.Enable {
failOnErr(errors.New("relay not available"), "Could not enable RLN Relay")
@ -26,7 +28,7 @@ func checkForRLN(options Options, nodeOpts *[]node.WakuNodeOption) {
ethPrivKey = options.RLNRelay.ETHPrivateKey
}
loaded, idKey, idCommitment, membershipIndex, err := getMembershipCredentials(options)
loaded, idKey, idCommitment, membershipIndex, err := getMembershipCredentials(logger, options)
failOnErr(err, "Invalid membership credentials")
loadedCredentialsFromFile = loaded
@ -41,14 +43,15 @@ func checkForRLN(options Options, nodeOpts *[]node.WakuNodeOption) {
options.RLNRelay.ETHClientAddress,
ethPrivKey,
options.RLNRelay.MembershipContractAddress,
nil,
))
}
}
}
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)
if options.RLNRelay.Enable && options.RLNRelay.Dynamic && !loadedCredentialsFromFile && options.RLNRelay.CredentialsPath != "" {
err := writeRLNMembershipCredentialsToFile(wakuNode.RLNRelay().MembershipKeyPair(), wakuNode.RLNRelay().MembershipIndex(), options.RLNRelay.CredentialsPath, []byte(options.KeyPasswd), options.Overwrite)
failOnErr(err, "Could not write membership credentials file")
}
}

View File

@ -44,7 +44,7 @@ type RelayOptions struct {
type RLNRelayOptions struct {
Enable bool
CredentialsFile string
CredentialsPath string
MembershipIndex int
PubsubTopic string
ContentTopic string

View File

@ -8,10 +8,12 @@ import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common"
"github.com/status-im/go-rln/rln"
"go.uber.org/zap"
)
type membershipCredentials struct {
@ -19,7 +21,11 @@ type membershipCredentials struct {
Index rln.MembershipIndex `json:"index"`
}
const RLN_CREDENTIALS_FILENAME = "rlnCredentials.txt"
func writeRLNMembershipCredentialsToFile(keyPair rln.MembershipKeyPair, idx rln.MembershipIndex, path string, passwd []byte, overwrite bool) error {
path = filepath.Join(path, RLN_CREDENTIALS_FILENAME)
if err := checkForFileExistence(path, overwrite); err != nil {
return err
}
@ -45,8 +51,8 @@ func writeRLNMembershipCredentialsToFile(keyPair rln.MembershipKeyPair, idx rln.
return ioutil.WriteFile(path, output, 0600)
}
func loadMembershipCredentialsFromFile(path string, passwd string) (rln.MembershipKeyPair, rln.MembershipIndex, error) {
src, err := ioutil.ReadFile(path)
func loadMembershipCredentialsFromFile(credentialsFilePath string, passwd string) (rln.MembershipKeyPair, rln.MembershipIndex, error) {
src, err := ioutil.ReadFile(credentialsFilePath)
if err != nil {
return rln.MembershipKeyPair{}, rln.MembershipIndex(0), err
}
@ -71,11 +77,13 @@ func loadMembershipCredentialsFromFile(path string, passwd string) (rln.Membersh
return credentials.Keypair, credentials.Index, err
}
func getMembershipCredentials(options Options) (fromFile bool, idKey *rln.IDKey, idCommitment *rln.IDCommitment, index rln.MembershipIndex, err error) {
if _, err = os.Stat(options.RLNRelay.CredentialsFile); err == nil {
if keyPair, index, err := loadMembershipCredentialsFromFile(options.RLNRelay.CredentialsFile, options.KeyPasswd); err != nil {
func getMembershipCredentials(logger *zap.Logger, options Options) (fromFile bool, idKey *rln.IDKey, idCommitment *rln.IDCommitment, index rln.MembershipIndex, err error) {
credentialsFilePath := filepath.Join(options.RLNRelay.CredentialsPath, RLN_CREDENTIALS_FILENAME)
if _, err = os.Stat(credentialsFilePath); err == nil {
if keyPair, index, err := loadMembershipCredentialsFromFile(credentialsFilePath, options.KeyPasswd); err != nil {
return false, nil, nil, rln.MembershipIndex(0), fmt.Errorf("could not read membership credentials file: %w", err)
} else {
logger.Info("loaded rln credentials", zap.String("filepath", credentialsFilePath))
return true, &keyPair.IDKey, &keyPair.IDCommitment, index, nil
}
}

View File

@ -54,9 +54,6 @@ func (w *WakuNode) mountRlnRelay() error {
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()
@ -84,7 +81,7 @@ func (w *WakuNode) mountRlnRelay() error {
// 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)
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.opts.rlnRegistrationHandler, w.log)
if err != nil {
return err
}

View File

@ -9,6 +9,7 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p-core/crypto"
@ -93,6 +94,7 @@ type WakuNodeParameters struct {
rlnETHPrivateKey *ecdsa.PrivateKey
rlnETHClientAddress string
rlnMembershipContractAddress common.Address
rlnRegistrationHandler func(tx *types.Transaction)
keepAliveInterval time.Duration

View File

@ -27,7 +27,7 @@ func WithStaticRLNRelay(pubsubTopic string, contentTopic string, memberIndex r.M
// WithStaticRLNRelay enables the Waku V2 RLN protocol in onchain mode.
// Requires the `gowaku_rln` build constrain (or the env variable RLN=true if building go-waku)
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 {
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, registrationHandler rln.RegistrationHandler) WakuNodeOption {
return func(params *WakuNodeParameters) error {
params.enableRLN = true
params.rlnRelayDynamic = true
@ -40,6 +40,7 @@ func WithDynamicRLNRelay(pubsubTopic string, contentTopic string, memberIndex r.
params.rlnETHClientAddress = ethClientAddress
params.rlnETHPrivateKey = ethPrivateKey
params.rlnMembershipContractAddress = membershipContractAddress
params.rlnRegistrationHandler = registrationHandler
return nil
}
}

View File

@ -85,6 +85,7 @@ func RlnRelayDynamic(
pubsubTopic string,
contentTopic string,
spamHandler SpamHandler,
registrationHandler RegistrationHandler,
log *zap.Logger,
) (*WakuRLNRelay, error) {
log = log.Named("rln-dynamic")
@ -114,6 +115,7 @@ func RlnRelayDynamic(
contentTopic: contentTopic,
log: log,
nullifierLog: make(map[r.Epoch][]r.ProofMetadata),
registrationHandler: registrationHandler,
}
// prepare rln membership key pair

View File

@ -10,6 +10,7 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
proto "github.com/golang/protobuf/proto"
"github.com/libp2p/go-libp2p-core/peer"
@ -26,6 +27,8 @@ const MAX_CLOCK_GAP_SECONDS = 20
// maximum allowed gap between the epochs of messages' RateLimitProofs
const MAX_EPOCH_GAP = int64(MAX_CLOCK_GAP_SECONDS / r.EPOCH_UNIT_SECONDS)
type RegistrationHandler = func(tx *types.Transaction)
type WakuRLNRelay struct {
ctx context.Context
@ -50,7 +53,8 @@ type WakuRLNRelay struct {
// the log of nullifiers and Shamir shares of the past messages grouped per epoch
nullifierLog map[r.Epoch][]r.ProofMetadata
log *zap.Logger
registrationHandler RegistrationHandler
log *zap.Logger
}
func (rln *WakuRLNRelay) Stop() {

View File

@ -10,6 +10,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
r "github.com/status-im/go-rln/rln"
"github.com/status-im/go-waku/waku/v2/protocol/rln/contracts"
"go.uber.org/zap"
@ -23,7 +24,7 @@ func toBigInt(i []byte) *big.Int {
return result
}
func register(ctx context.Context, idComm r.IDCommitment, ethAccountPrivateKey *ecdsa.PrivateKey, ethClientAddress string, membershipContractAddress common.Address, log *zap.Logger) (*r.MembershipIndex, error) {
func register(ctx context.Context, idComm r.IDCommitment, ethAccountPrivateKey *ecdsa.PrivateKey, ethClientAddress string, membershipContractAddress common.Address, registrationHandler RegistrationHandler, log *zap.Logger) (*r.MembershipIndex, error) {
backend, err := ethclient.Dial(ethClientAddress)
if err != nil {
return nil, err
@ -57,6 +58,10 @@ func register(ctx context.Context, idComm r.IDCommitment, ethAccountPrivateKey *
log.Info("transaction broadcasted", zap.String("transactionHash", tx.Hash().Hex()))
if registrationHandler != nil {
registrationHandler(tx)
}
txReceipt, err := bind.WaitMined(ctx, backend, tx)
if err != nil {
return nil, err
@ -95,7 +100,7 @@ func register(ctx context.Context, idComm r.IDCommitment, ethAccountPrivateKey *
// into the membership contract whose address is in rlnPeer.membershipContractAddress
func (rln *WakuRLNRelay) Register(ctx context.Context) (*r.MembershipIndex, error) {
pk := rln.membershipKeyPair.IDCommitment
return register(ctx, pk, rln.ethAccountPrivateKey, rln.ethClientAddress, rln.membershipContractAddress, rln.log)
return register(ctx, pk, rln.ethAccountPrivateKey, rln.ethClientAddress, rln.membershipContractAddress, rln.registrationHandler, rln.log)
}
// the types of inputs to this handler matches the MemberRegistered event/proc defined in the MembershipContract interface
@ -146,7 +151,7 @@ func (rln *WakuRLNRelay) HandleGroupUpdates(handler RegistrationEventHandler, er
select {
case <-doneCh:
return
case <-errCh:
case err := <-errCh:
errChan <- err
return
}
@ -179,7 +184,11 @@ func (rln *WakuRLNRelay) watchNewEvents(rlnContract *contracts.RLN, handler Regi
logSink := make(chan *contracts.RLNMemberRegistered)
subs, err := rlnContract.WatchMemberRegistered(&bind.WatchOpts{Context: rln.ctx, Start: nil}, logSink)
if err != nil {
if err == rpc.ErrNotificationsUnsupported {
err = errors.New("notifications not supported. The node must support websockets")
}
errCh <- err
return
}
defer subs.Unsubscribe()
@ -197,10 +206,11 @@ func (rln *WakuRLNRelay) watchNewEvents(rlnContract *contracts.RLN, handler Regi
close(logSink)
return
case err := <-subs.Err():
close(logSink)
if err != nil {
rln.log.Error("watching new events", zap.Error(err))
errCh <- err
}
close(logSink)
return
}
}

View File

@ -118,6 +118,7 @@ components:
properties:
payload:
type: string
format: byte
contentTopic:
$ref: '#/components/schemas/ContentTopic'
version:

View File

@ -53,7 +53,7 @@ func rlnFlags() []cli.Flag {
Name: "rln-relay-membership-credentials-file",
Usage: "RLN relay membership credentials file",
Value: "rlnCredentials.txt",
Destination: &options.RLNRelay.CredentialsFile,
Destination: &options.RLNRelay.CredentialsPath,
},
// TODO: this is a good candidate option for subcommands
// TODO: consider accepting a private key file and passwd