-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: rln subcommands #654
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "waku/v2/protocol/rln/contracts/rln-contract"] | ||
path = waku/v2/protocol/rln/contracts/rln-contract | ||
url = [email protected]:vacp2p/rln-contract.git | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
//go:build !gowaku_rln | ||
// +build !gowaku_rln | ||
|
||
package rlngenerate | ||
|
||
import ( | ||
"errors" | ||
|
||
cli "github.com/urfave/cli/v2" | ||
) | ||
|
||
// Command generates a key file used to generate the node's peerID, encrypted with an optional password | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Node's peerId maynot be tied to RLN membership right. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct. the peerID is not associated to rln. User is able to choose which credential to use via the membership group and keystore index flags |
||
var Command = cli.Command{ | ||
Name: "generate-rln-credentials", | ||
Usage: "Generate credentials for usage with RLN", | ||
Action: func(cCtx *cli.Context) error { | ||
return errors.New("not available. Execute `make RLN=true` to add RLN support to go-waku") | ||
}, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
//go:build gowaku_rln | ||
// +build gowaku_rln | ||
|
||
package rlngenerate | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"math/big" | ||
|
||
"github.com/ethereum/go-ethereum/ethclient" | ||
cli "github.com/urfave/cli/v2" | ||
"github.com/waku-org/go-waku/logging" | ||
"github.com/waku-org/go-waku/waku/v2/protocol/rln/contracts" | ||
"github.com/waku-org/go-waku/waku/v2/protocol/rln/group_manager/dynamic" | ||
"github.com/waku-org/go-waku/waku/v2/protocol/rln/keystore" | ||
"github.com/waku-org/go-waku/waku/v2/utils" | ||
"github.com/waku-org/go-zerokit-rln/rln" | ||
"go.uber.org/zap" | ||
) | ||
|
||
var options Options | ||
var logger = utils.Logger().Named("rln-credentials") | ||
|
||
// Command generates a key file used to generate the node's peerID, encrypted with an optional password | ||
var Command = cli.Command{ | ||
Name: "generate-rln-credentials", | ||
Usage: "Generate credentials for usage with RLN", | ||
Action: func(cCtx *cli.Context) error { | ||
err := verifyFlags() | ||
if err != nil { | ||
logger.Error("validating option flags", zap.Error(err)) | ||
return cli.Exit(err, 1) | ||
} | ||
|
||
err = execute(context.Background()) | ||
if err != nil { | ||
logger.Error("registering RLN credentials", zap.Error(err)) | ||
return cli.Exit(err, 1) | ||
} | ||
|
||
return nil | ||
}, | ||
Flags: flags, | ||
} | ||
|
||
func verifyFlags() error { | ||
if options.CredentialsPath == "" { | ||
logger.Warn("keystore: no credentials path set, using default path", zap.String("path", keystore.RLN_CREDENTIALS_FILENAME)) | ||
options.CredentialsPath = keystore.RLN_CREDENTIALS_FILENAME | ||
} | ||
|
||
if options.CredentialsPassword == "" { | ||
logger.Warn("keystore: no credentials password set, using default password", zap.String("password", keystore.RLN_CREDENTIALS_PASSWORD)) | ||
options.CredentialsPassword = keystore.RLN_CREDENTIALS_PASSWORD | ||
} | ||
|
||
if options.ETHPrivateKey == nil { | ||
return errors.New("a private key must be specified") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func execute(ctx context.Context) error { | ||
ethClient, err := ethclient.Dial(options.ETHClientAddress) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
rlnInstance, err := rln.NewRLN() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
chainID, err := ethClient.ChainID(ctx) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
rlnContract, err := contracts.NewRLN(options.MembershipContractAddress, ethClient) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// prepare rln membership key pair | ||
logger.Info("generating rln credential") | ||
identityCredential, err := rlnInstance.MembershipKeyGen() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// register the rln-relay peer to the membership contract | ||
membershipIndex, err := register(ctx, ethClient, rlnContract, identityCredential.IDCommitment, chainID) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// TODO: clean private key from memory | ||
|
||
err = persistCredentials(identityCredential, membershipIndex, chainID) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if logger.Level() == zap.DebugLevel { | ||
logger.Info("registered credentials into the membership contract", | ||
logging.HexString("IDCommitment", identityCredential.IDCommitment[:]), | ||
logging.HexString("IDNullifier", identityCredential.IDNullifier[:]), | ||
logging.HexString("IDSecretHash", identityCredential.IDSecretHash[:]), | ||
logging.HexString("IDTrapDoor", identityCredential.IDTrapdoor[:]), | ||
zap.Uint("index", membershipIndex), | ||
) | ||
} else { | ||
logger.Info("registered credentials into the membership contract", logging.HexString("idCommitment", identityCredential.IDCommitment[:]), zap.Uint("index", membershipIndex)) | ||
} | ||
|
||
ethClient.Close() | ||
|
||
return nil | ||
} | ||
|
||
func persistCredentials(identityCredential *rln.IdentityCredential, membershipIndex rln.MembershipIndex, chainID *big.Int) error { | ||
membershipGroup := keystore.MembershipGroup{ | ||
TreeIndex: membershipIndex, | ||
MembershipContract: keystore.MembershipContract{ | ||
ChainId: fmt.Sprintf("0x%X", chainID.Int64()), | ||
Address: options.MembershipContractAddress.String(), | ||
}, | ||
} | ||
|
||
membershipGroupIndex, err := keystore.AddMembershipCredentials(options.CredentialsPath, identityCredential, membershipGroup, options.CredentialsPassword, dynamic.RLNAppInfo, keystore.DefaultSeparator) | ||
if err != nil { | ||
return fmt.Errorf("failed to persist credentials: %w", err) | ||
} | ||
|
||
// TODO: obtain keystore index? | ||
logger.Info("persisted credentials succesfully", zap.Uint("membershipGroupIndex", membershipGroupIndex)) | ||
|
||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
//go:build gowaku_rln | ||
// +build gowaku_rln | ||
|
||
package rlngenerate | ||
|
||
import ( | ||
cli "github.com/urfave/cli/v2" | ||
wcli "github.com/waku-org/go-waku/waku/cliutils" | ||
"github.com/waku-org/go-waku/waku/v2/protocol/rln/keystore" | ||
) | ||
|
||
var flags = []cli.Flag{ | ||
&cli.PathFlag{ | ||
Name: "cred-path", | ||
Usage: "RLN relay membership credentials file", | ||
Value: keystore.RLN_CREDENTIALS_FILENAME, | ||
Destination: &options.CredentialsPath, | ||
}, | ||
&cli.StringFlag{ | ||
Name: "cred-password", | ||
Value: keystore.RLN_CREDENTIALS_PASSWORD, | ||
Usage: "Password for encrypting RLN credentials", | ||
Destination: &options.CredentialsPassword, | ||
}, | ||
&cli.GenericFlag{ | ||
Name: "eth-account-private-key", | ||
Usage: "Ethereum account private key used for registering in member contract", | ||
Value: &wcli.PrivateKeyValue{ | ||
Value: &options.ETHPrivateKey, | ||
}, | ||
}, | ||
&cli.StringFlag{ | ||
Name: "eth-client-address", | ||
Usage: "Ethereum testnet client address", | ||
Value: "ws://localhost:8545", | ||
Destination: &options.ETHClientAddress, | ||
}, | ||
&cli.GenericFlag{ | ||
Name: "eth-contract-address", | ||
Usage: "Address of membership contract", | ||
Value: &wcli.AddressValue{ | ||
Value: &options.MembershipContractAddress, | ||
}, | ||
}, | ||
&cli.StringFlag{ | ||
Name: "eth-nonce", | ||
Value: "", | ||
Usage: "Set an specific ETH transaction nonce. Leave empty to calculate the nonce automatically", | ||
Destination: &options.ETHNonce, | ||
}, | ||
&cli.Uint64Flag{ | ||
Name: "eth-gas-limit", | ||
Value: 0, | ||
Usage: "Gas limit to set for the transaction execution (0 = estimate)", | ||
Destination: &options.ETHGasLimit, | ||
}, | ||
&cli.StringFlag{ | ||
Name: "eth-gas-price", | ||
Value: "", | ||
Usage: "Gas price in wei to use for the transaction execution (empty = gas price oracle)", | ||
Destination: &options.ETHGasPrice, | ||
}, | ||
&cli.StringFlag{ | ||
Name: "eth-gas-fee-cap", | ||
Value: "", | ||
Usage: "Gas fee cap in wei to use for the 1559 transaction execution (empty = gas price oracle)", | ||
Destination: &options.ETHGasFeeCap, | ||
}, | ||
&cli.StringFlag{ | ||
Name: "eth-gas-tip-cap", | ||
Value: "", | ||
Usage: "Gas priority fee cap in wei to use for the 1559 transaction execution (empty = gas price oracle)", | ||
Destination: &options.ETHGasTipCap, | ||
}, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package rlngenerate | ||
|
||
import ( | ||
"crypto/ecdsa" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
) | ||
|
||
// Options are settings used to create RLN credentials. | ||
type Options struct { | ||
CredentialsPath string | ||
CredentialsPassword string | ||
ETHPrivateKey *ecdsa.PrivateKey | ||
ETHClientAddress string | ||
MembershipContractAddress common.Address | ||
ETHGasLimit uint64 | ||
ETHNonce string | ||
ETHGasPrice string | ||
ETHGasFeeCap string | ||
ETHGasTipCap string | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
err we should use the waku-org/waku-rln-contract now!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using waku-rln-contract
WakuRlnRegistry
introduces a lot of breaking changes, due to how the bindings for go are modified and I end up not being able to retrieve the events:Notice how I can't easily filter events, nor obtain the fee.
Since @alrevuelta is still using vacp2p/rln-contract, I'll figure out how to solve the errors introduced by changing the contract in a separate PR.