mirror of
https://github.com/status-im/go-waku.git
synced 2025-02-26 12:07:34 +00:00
refactor: use a map to store credentials instead of an array
This commit is contained in:
parent
0854edaf3d
commit
9c0bebc859
@ -9,3 +9,6 @@ plugins:
|
|||||||
#enabled: true
|
#enabled: true
|
||||||
exclude_patterns:
|
exclude_patterns:
|
||||||
- "."
|
- "."
|
||||||
|
- "**/*.pb.go"
|
||||||
|
- "**/rln/contracts/*.go"
|
||||||
|
- "**/bindata.go"
|
||||||
|
@ -6,6 +6,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
cli "github.com/urfave/cli/v2"
|
cli "github.com/urfave/cli/v2"
|
||||||
wcli "github.com/waku-org/go-waku/waku/cliutils"
|
wcli "github.com/waku-org/go-waku/waku/cliutils"
|
||||||
|
"github.com/waku-org/go-waku/waku/v2/protocol/rln/keystore"
|
||||||
)
|
)
|
||||||
|
|
||||||
func rlnFlags() []cli.Flag {
|
func rlnFlags() []cli.Flag {
|
||||||
@ -17,10 +18,10 @@ func rlnFlags() []cli.Flag {
|
|||||||
Destination: &options.RLNRelay.Enable,
|
Destination: &options.RLNRelay.Enable,
|
||||||
},
|
},
|
||||||
&cli.UintFlag{
|
&cli.UintFlag{
|
||||||
Name: "rln-relay-membership-group-index",
|
Name: "rln-relay-membership-index",
|
||||||
Value: 0,
|
Value: 0,
|
||||||
Usage: "the index of credentials to use, within a specific rln membership set",
|
Usage: "the index of credentials to use",
|
||||||
Destination: &options.RLNRelay.MembershipGroupIndex,
|
Destination: &options.RLNRelay.MembershipIndex,
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "rln-relay-dynamic",
|
Name: "rln-relay-dynamic",
|
||||||
@ -30,12 +31,12 @@ func rlnFlags() []cli.Flag {
|
|||||||
&cli.PathFlag{
|
&cli.PathFlag{
|
||||||
Name: "rln-relay-cred-path",
|
Name: "rln-relay-cred-path",
|
||||||
Usage: "RLN relay membership credentials file",
|
Usage: "RLN relay membership credentials file",
|
||||||
Value: "",
|
Value: keystore.DefaultCredentialsFilename,
|
||||||
Destination: &options.RLNRelay.CredentialsPath,
|
Destination: &options.RLNRelay.CredentialsPath,
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "rln-relay-cred-password",
|
Name: "rln-relay-cred-password",
|
||||||
Value: "",
|
Value: keystore.DefaultCredentialsPassword,
|
||||||
Usage: "Password for encrypting RLN credentials",
|
Usage: "Password for encrypting RLN credentials",
|
||||||
Destination: &options.RLNRelay.CredentialsPassword,
|
Destination: &options.RLNRelay.CredentialsPassword,
|
||||||
},
|
},
|
||||||
@ -45,12 +46,6 @@ func rlnFlags() []cli.Flag {
|
|||||||
Usage: "Path to the RLN merkle tree sled db (https://github.com/spacejam/sled)",
|
Usage: "Path to the RLN merkle tree sled db (https://github.com/spacejam/sled)",
|
||||||
Destination: &options.RLNRelay.TreePath,
|
Destination: &options.RLNRelay.TreePath,
|
||||||
},
|
},
|
||||||
&cli.UintFlag{
|
|
||||||
Name: "rln-relay-membership-index",
|
|
||||||
Value: 0,
|
|
||||||
Usage: "the index of credentials to use",
|
|
||||||
Destination: &options.RLNRelay.CredentialsIndex,
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "rln-relay-eth-client-address",
|
Name: "rln-relay-eth-client-address",
|
||||||
Usage: "Ethereum testnet client address",
|
Usage: "Ethereum testnet client address",
|
||||||
|
@ -17,17 +17,16 @@ func checkForRLN(logger *zap.Logger, options NodeOptions, nodeOpts *[]node.WakuN
|
|||||||
failOnErr(errors.New("relay not available"), "Could not enable RLN Relay")
|
failOnErr(errors.New("relay not available"), "Could not enable RLN Relay")
|
||||||
}
|
}
|
||||||
if !options.RLNRelay.Dynamic {
|
if !options.RLNRelay.Dynamic {
|
||||||
*nodeOpts = append(*nodeOpts, node.WithStaticRLNRelay(rln.MembershipIndex(options.RLNRelay.MembershipGroupIndex), nil))
|
*nodeOpts = append(*nodeOpts, node.WithStaticRLNRelay(rln.MembershipIndex(options.RLNRelay.MembershipIndex), nil))
|
||||||
} else {
|
} else {
|
||||||
// TODO: too many parameters in this function
|
// TODO: too many parameters in this function
|
||||||
// consider passing a config struct instead
|
// consider passing a config struct instead
|
||||||
*nodeOpts = append(*nodeOpts, node.WithDynamicRLNRelay(
|
*nodeOpts = append(*nodeOpts, node.WithDynamicRLNRelay(
|
||||||
options.RLNRelay.CredentialsPath,
|
options.RLNRelay.CredentialsPath,
|
||||||
options.RLNRelay.CredentialsPassword,
|
options.RLNRelay.CredentialsPassword,
|
||||||
options.RLNRelay.CredentialsIndex,
|
|
||||||
options.RLNRelay.TreePath,
|
options.RLNRelay.TreePath,
|
||||||
options.RLNRelay.MembershipContractAddress,
|
options.RLNRelay.MembershipContractAddress,
|
||||||
rln.MembershipIndex(options.RLNRelay.MembershipGroupIndex),
|
rln.MembershipIndex(options.RLNRelay.MembershipIndex),
|
||||||
nil,
|
nil,
|
||||||
options.RLNRelay.ETHClientAddress,
|
options.RLNRelay.ETHClientAddress,
|
||||||
))
|
))
|
||||||
|
@ -37,9 +37,8 @@ type RLNRelayOptions struct {
|
|||||||
Enable bool
|
Enable bool
|
||||||
CredentialsPath string
|
CredentialsPath string
|
||||||
CredentialsPassword string
|
CredentialsPassword string
|
||||||
CredentialsIndex uint
|
|
||||||
TreePath string
|
TreePath string
|
||||||
MembershipGroupIndex uint
|
MembershipIndex uint
|
||||||
Dynamic bool
|
Dynamic bool
|
||||||
ETHClientAddress string
|
ETHClientAddress string
|
||||||
MembershipContractAddress common.Address
|
MembershipContractAddress common.Address
|
||||||
|
@ -103,27 +103,24 @@ func execute(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func persistCredentials(identityCredential *rln.IdentityCredential, membershipIndex rln.MembershipIndex, chainID *big.Int) error {
|
func persistCredentials(identityCredential *rln.IdentityCredential, treeIndex rln.MembershipIndex, chainID *big.Int) error {
|
||||||
appKeystore, err := keystore.New(options.CredentialsPath, dynamic.RLNAppInfo, logger)
|
appKeystore, err := keystore.New(options.CredentialsPath, dynamic.RLNAppInfo, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
membershipGroup := keystore.MembershipGroup{
|
membershipCredential := keystore.MembershipCredentials{
|
||||||
TreeIndex: membershipIndex,
|
IdentityCredential: identityCredential,
|
||||||
MembershipContract: keystore.MembershipContract{
|
TreeIndex: treeIndex,
|
||||||
ChainID: fmt.Sprintf("0x%X", chainID.Int64()),
|
MembershipContractInfo: keystore.NewMembershipContractInfo(chainID, options.MembershipContractAddress),
|
||||||
Address: options.MembershipContractAddress.String(),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
membershipGroupIndex, err := appKeystore.AddMembershipCredentials(identityCredential, membershipGroup, options.CredentialsPassword)
|
err = appKeystore.AddMembershipCredentials(membershipCredential, options.CredentialsPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to persist credentials: %w", err)
|
return fmt.Errorf("failed to persist credentials: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: obtain keystore index?
|
logger.Info("persisted credentials succesfully")
|
||||||
logger.Info("persisted credentials succesfully", zap.Uint("membershipGroupIndex", membershipGroupIndex))
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -468,11 +468,7 @@ func (c *Chat) welcomeMessage() {
|
|||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
idx, err := c.node.RLNRelay().MembershipIndex()
|
idx := c.node.RLNRelay().MembershipIndex()
|
||||||
if err != nil {
|
|
||||||
c.ui.Quit()
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
idTrapdoor := credential.IDTrapdoor
|
idTrapdoor := credential.IDTrapdoor
|
||||||
idNullifier := credential.IDSecretHash
|
idNullifier := credential.IDSecretHash
|
||||||
|
@ -52,7 +52,6 @@ func execute(options Options) {
|
|||||||
opts = append(opts, node.WithDynamicRLNRelay(
|
opts = append(opts, node.WithDynamicRLNRelay(
|
||||||
options.RLNRelay.CredentialsPath,
|
options.RLNRelay.CredentialsPath,
|
||||||
options.RLNRelay.CredentialsPassword,
|
options.RLNRelay.CredentialsPassword,
|
||||||
options.RLNRelay.CredentialsIndex,
|
|
||||||
"", // Will use default tree path
|
"", // Will use default tree path
|
||||||
options.RLNRelay.MembershipContractAddress,
|
options.RLNRelay.MembershipContractAddress,
|
||||||
uint(options.RLNRelay.MembershipIndex),
|
uint(options.RLNRelay.MembershipIndex),
|
||||||
|
@ -185,17 +185,11 @@ func getFlags() []cli.Flag {
|
|||||||
Usage: "Enable spam protection through rln-relay",
|
Usage: "Enable spam protection through rln-relay",
|
||||||
Destination: &options.RLNRelay.Enable,
|
Destination: &options.RLNRelay.Enable,
|
||||||
},
|
},
|
||||||
&cli.UintFlag{
|
|
||||||
Name: "rln-relay-membership-group-index",
|
|
||||||
Value: 0,
|
|
||||||
Usage: "the index of credentials to use, within a specific rln membership set",
|
|
||||||
Destination: &options.RLNRelay.MembershipGroupIndex,
|
|
||||||
},
|
|
||||||
&cli.UintFlag{
|
&cli.UintFlag{
|
||||||
Name: "rln-relay-membership-index",
|
Name: "rln-relay-membership-index",
|
||||||
Value: 0,
|
Value: 0,
|
||||||
Usage: "the index of credentials to use",
|
Usage: "the index of credentials to use",
|
||||||
Destination: &options.RLNRelay.CredentialsIndex,
|
Destination: &options.RLNRelay.MembershipIndex,
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "rln-relay-dynamic",
|
Name: "rln-relay-dynamic",
|
||||||
|
@ -31,8 +31,6 @@ type RLNRelayOptions struct {
|
|||||||
Enable bool
|
Enable bool
|
||||||
CredentialsPath string
|
CredentialsPath string
|
||||||
CredentialsPassword string
|
CredentialsPassword string
|
||||||
CredentialsIndex uint
|
|
||||||
MembershipGroupIndex uint
|
|
||||||
MembershipIndex uint
|
MembershipIndex uint
|
||||||
Dynamic bool
|
Dynamic bool
|
||||||
ETHClientAddress string
|
ETHClientAddress string
|
||||||
|
@ -29,8 +29,7 @@ const ethClientAddress = "wss://sepolia.infura.io/ws/v3/API_KEY_GOES_HERE"
|
|||||||
const contractAddress = "0x9C09146844C1326c2dBC41c451766C7138F88155"
|
const contractAddress = "0x9C09146844C1326c2dBC41c451766C7138F88155"
|
||||||
const keystorePath = "" // Empty to store in current folder
|
const keystorePath = "" // Empty to store in current folder
|
||||||
const keystorePassword = "" // Empty to use default
|
const keystorePassword = "" // Empty to use default
|
||||||
const keystoreIndex = 0
|
const membershipIndex = 0
|
||||||
const membershipGroupIndex = 0
|
|
||||||
|
|
||||||
var contentTopic = protocol.NewContentTopic("rln", 1, "test", "proto").String()
|
var contentTopic = protocol.NewContentTopic("rln", 1, "test", "proto").String()
|
||||||
var pubsubTopic = protocol.DefaultPubsubTopic()
|
var pubsubTopic = protocol.DefaultPubsubTopic()
|
||||||
@ -63,14 +62,11 @@ func main() {
|
|||||||
node.WithNTP(),
|
node.WithNTP(),
|
||||||
node.WithWakuRelay(),
|
node.WithWakuRelay(),
|
||||||
node.WithDynamicRLNRelay(
|
node.WithDynamicRLNRelay(
|
||||||
pubsubTopic.String(),
|
|
||||||
contentTopic,
|
|
||||||
keystorePath,
|
keystorePath,
|
||||||
keystorePassword,
|
keystorePassword,
|
||||||
keystoreIndex,
|
|
||||||
"", // Will use default tree path
|
"", // Will use default tree path
|
||||||
common.HexToAddress(contractAddress),
|
common.HexToAddress(contractAddress),
|
||||||
membershipGroupIndex,
|
membershipIndex,
|
||||||
spamHandler,
|
spamHandler,
|
||||||
ethClientAddress,
|
ethClientAddress,
|
||||||
),
|
),
|
||||||
|
@ -70,7 +70,7 @@ type SpamHandler = func(message *pb.WakuMessage) error
|
|||||||
|
|
||||||
type RLNRelay interface {
|
type RLNRelay interface {
|
||||||
IdentityCredential() (IdentityCredential, error)
|
IdentityCredential() (IdentityCredential, error)
|
||||||
MembershipIndex() (uint, error)
|
MembershipIndex() uint
|
||||||
AppendRLNProof(msg *pb.WakuMessage, senderEpochTime time.Time) error
|
AppendRLNProof(msg *pb.WakuMessage, senderEpochTime time.Time) error
|
||||||
Validator(spamHandler SpamHandler) func(ctx context.Context, peerID peer.ID, message *pubsub.Message) bool
|
Validator(spamHandler SpamHandler) func(ctx context.Context, peerID peer.ID, message *pubsub.Message) bool
|
||||||
Start(ctx context.Context) error
|
Start(ctx context.Context) error
|
||||||
|
@ -56,7 +56,6 @@ func (w *WakuNode) setupRLNRelay() error {
|
|||||||
w.opts.rlnRelayMemIndex,
|
w.opts.rlnRelayMemIndex,
|
||||||
appKeystore,
|
appKeystore,
|
||||||
w.opts.keystorePassword,
|
w.opts.keystorePassword,
|
||||||
w.opts.keystoreIndex,
|
|
||||||
w.opts.prometheusReg,
|
w.opts.prometheusReg,
|
||||||
w.log,
|
w.log,
|
||||||
)
|
)
|
||||||
|
@ -100,7 +100,6 @@ type WakuNodeParameters struct {
|
|||||||
rlnETHClientAddress string
|
rlnETHClientAddress string
|
||||||
keystorePath string
|
keystorePath string
|
||||||
keystorePassword string
|
keystorePassword string
|
||||||
keystoreIndex uint
|
|
||||||
rlnTreePath string
|
rlnTreePath string
|
||||||
rlnMembershipContractAddress common.Address
|
rlnMembershipContractAddress common.Address
|
||||||
|
|
||||||
|
@ -23,17 +23,16 @@ func WithStaticRLNRelay(memberIndex r.MembershipIndex, spamHandler rln.SpamHandl
|
|||||||
|
|
||||||
// WithDynamicRLNRelay enables the Waku V2 RLN protocol in onchain mode.
|
// WithDynamicRLNRelay 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)
|
// Requires the `gowaku_rln` build constrain (or the env variable RLN=true if building go-waku)
|
||||||
func WithDynamicRLNRelay(keystorePath string, keystorePassword string, keystoreIndex uint, treePath string, membershipContract common.Address, membershipGroupIndex uint, spamHandler rln.SpamHandler, ethClientAddress string) WakuNodeOption {
|
func WithDynamicRLNRelay(keystorePath string, keystorePassword string, treePath string, membershipContract common.Address, membershipIndex uint, spamHandler rln.SpamHandler, ethClientAddress string) WakuNodeOption {
|
||||||
return func(params *WakuNodeParameters) error {
|
return func(params *WakuNodeParameters) error {
|
||||||
params.enableRLN = true
|
params.enableRLN = true
|
||||||
params.rlnRelayDynamic = true
|
params.rlnRelayDynamic = true
|
||||||
params.keystorePassword = keystorePassword
|
params.keystorePassword = keystorePassword
|
||||||
params.keystorePath = keystorePath
|
params.keystorePath = keystorePath
|
||||||
params.keystoreIndex = keystoreIndex
|
|
||||||
params.rlnSpamHandler = spamHandler
|
params.rlnSpamHandler = spamHandler
|
||||||
params.rlnETHClientAddress = ethClientAddress
|
params.rlnETHClientAddress = ethClientAddress
|
||||||
params.rlnMembershipContractAddress = membershipContract
|
params.rlnMembershipContractAddress = membershipContract
|
||||||
params.rlnRelayMemIndex = membershipGroupIndex
|
params.rlnRelayMemIndex = membershipIndex
|
||||||
params.rlnTreePath = treePath
|
params.rlnTreePath = treePath
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package dynamic
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -25,7 +24,7 @@ import (
|
|||||||
var RLNAppInfo = keystore.AppInfo{
|
var RLNAppInfo = keystore.AppInfo{
|
||||||
Application: "waku-rln-relay",
|
Application: "waku-rln-relay",
|
||||||
AppIdentifier: "01234567890abcdef",
|
AppIdentifier: "01234567890abcdef",
|
||||||
Version: "0.1",
|
Version: "0.2",
|
||||||
}
|
}
|
||||||
|
|
||||||
type DynamicGroupManager struct {
|
type DynamicGroupManager struct {
|
||||||
@ -37,10 +36,9 @@ type DynamicGroupManager struct {
|
|||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
|
|
||||||
identityCredential *rln.IdentityCredential
|
identityCredential *rln.IdentityCredential
|
||||||
membershipIndex *rln.MembershipIndex
|
membershipIndex rln.MembershipIndex
|
||||||
|
|
||||||
membershipContractAddress common.Address
|
membershipContractAddress common.Address
|
||||||
membershipGroupIndex uint
|
|
||||||
ethClientAddress string
|
ethClientAddress string
|
||||||
ethClient *ethclient.Client
|
ethClient *ethclient.Client
|
||||||
|
|
||||||
@ -53,7 +51,6 @@ type DynamicGroupManager struct {
|
|||||||
|
|
||||||
appKeystore *keystore.AppKeystore
|
appKeystore *keystore.AppKeystore
|
||||||
keystorePassword string
|
keystorePassword string
|
||||||
keystoreIndex uint
|
|
||||||
|
|
||||||
rootTracker *group_manager.MerkleRootTracker
|
rootTracker *group_manager.MerkleRootTracker
|
||||||
}
|
}
|
||||||
@ -120,23 +117,21 @@ type RegistrationHandler = func(tx *types.Transaction)
|
|||||||
func NewDynamicGroupManager(
|
func NewDynamicGroupManager(
|
||||||
ethClientAddr string,
|
ethClientAddr string,
|
||||||
memContractAddr common.Address,
|
memContractAddr common.Address,
|
||||||
membershipGroupIndex uint,
|
membershipIndex uint,
|
||||||
appKeystore *keystore.AppKeystore,
|
appKeystore *keystore.AppKeystore,
|
||||||
keystorePassword string,
|
keystorePassword string,
|
||||||
keystoreIndex uint,
|
|
||||||
reg prometheus.Registerer,
|
reg prometheus.Registerer,
|
||||||
log *zap.Logger,
|
log *zap.Logger,
|
||||||
) (*DynamicGroupManager, error) {
|
) (*DynamicGroupManager, error) {
|
||||||
log = log.Named("rln-dynamic")
|
log = log.Named("rln-dynamic")
|
||||||
|
|
||||||
return &DynamicGroupManager{
|
return &DynamicGroupManager{
|
||||||
membershipGroupIndex: membershipGroupIndex,
|
membershipIndex: membershipIndex,
|
||||||
membershipContractAddress: memContractAddr,
|
membershipContractAddress: memContractAddr,
|
||||||
ethClientAddress: ethClientAddr,
|
ethClientAddress: ethClientAddr,
|
||||||
eventHandler: handler,
|
eventHandler: handler,
|
||||||
appKeystore: appKeystore,
|
appKeystore: appKeystore,
|
||||||
keystorePassword: keystorePassword,
|
keystorePassword: keystorePassword,
|
||||||
keystoreIndex: keystoreIndex,
|
|
||||||
log: log,
|
log: log,
|
||||||
metrics: newMetrics(reg),
|
metrics: newMetrics(reg),
|
||||||
}, nil
|
}, nil
|
||||||
@ -198,30 +193,18 @@ func (gm *DynamicGroupManager) loadCredential() error {
|
|||||||
|
|
||||||
credentials, err := gm.appKeystore.GetMembershipCredentials(
|
credentials, err := gm.appKeystore.GetMembershipCredentials(
|
||||||
gm.keystorePassword,
|
gm.keystorePassword,
|
||||||
nil,
|
gm.membershipIndex,
|
||||||
[]keystore.MembershipContract{{
|
keystore.NewMembershipContractInfo(gm.chainId, gm.membershipContractAddress))
|
||||||
ChainID: fmt.Sprintf("0x%X", gm.chainId),
|
|
||||||
Address: gm.membershipContractAddress.Hex(),
|
|
||||||
}})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
gm.metrics.RecordMembershipCredentialsImportDuration(time.Since(start))
|
gm.metrics.RecordMembershipCredentialsImportDuration(time.Since(start))
|
||||||
|
|
||||||
if len(credentials) == 0 {
|
if credentials == nil {
|
||||||
return errors.New("no credentials available")
|
return errors.New("no credentials available")
|
||||||
}
|
}
|
||||||
|
|
||||||
if int(gm.keystoreIndex) > len(credentials)-1 {
|
gm.identityCredential = credentials.IdentityCredential
|
||||||
return errors.New("invalid keystore index")
|
|
||||||
}
|
|
||||||
|
|
||||||
if int(gm.membershipGroupIndex) > len(credentials[gm.keystoreIndex].MembershipGroups)-1 {
|
|
||||||
return errors.New("invalid membership group index")
|
|
||||||
}
|
|
||||||
|
|
||||||
gm.identityCredential = credentials[gm.keystoreIndex].IdentityCredential
|
|
||||||
gm.membershipIndex = &credentials[gm.keystoreIndex].MembershipGroups[gm.membershipGroupIndex].TreeIndex
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -282,12 +265,8 @@ func (gm *DynamicGroupManager) IdentityCredentials() (rln.IdentityCredential, er
|
|||||||
return *gm.identityCredential, nil
|
return *gm.identityCredential, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gm *DynamicGroupManager) MembershipIndex() (rln.MembershipIndex, error) {
|
func (gm *DynamicGroupManager) MembershipIndex() rln.MembershipIndex {
|
||||||
if gm.membershipIndex == nil {
|
return gm.membershipIndex
|
||||||
return 0, errors.New("membership index has not been setup")
|
|
||||||
}
|
|
||||||
|
|
||||||
return *gm.membershipIndex, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop stops all go-routines, eth client and closes the rln database
|
// Stop stops all go-routines, eth client and closes the rln database
|
||||||
|
@ -14,7 +14,7 @@ type StaticGroupManager struct {
|
|||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
|
|
||||||
identityCredential *rln.IdentityCredential
|
identityCredential *rln.IdentityCredential
|
||||||
membershipIndex *rln.MembershipIndex
|
membershipIndex rln.MembershipIndex
|
||||||
|
|
||||||
group []rln.IDCommitment
|
group []rln.IDCommitment
|
||||||
rootTracker *group_manager.MerkleRootTracker
|
rootTracker *group_manager.MerkleRootTracker
|
||||||
@ -36,7 +36,7 @@ func NewStaticGroupManager(
|
|||||||
log: log.Named("rln-static"),
|
log: log.Named("rln-static"),
|
||||||
group: group,
|
group: group,
|
||||||
identityCredential: &identityCredential,
|
identityCredential: &identityCredential,
|
||||||
membershipIndex: &index,
|
membershipIndex: index,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,12 +85,8 @@ func (gm *StaticGroupManager) IdentityCredentials() (rln.IdentityCredential, err
|
|||||||
return *gm.identityCredential, nil
|
return *gm.identityCredential, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gm *StaticGroupManager) MembershipIndex() (rln.MembershipIndex, error) {
|
func (gm *StaticGroupManager) MembershipIndex() rln.MembershipIndex {
|
||||||
if gm.membershipIndex == nil {
|
return gm.membershipIndex
|
||||||
return 0, errors.New("membership index has not been setup")
|
|
||||||
}
|
|
||||||
|
|
||||||
return *gm.membershipIndex, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop is a function created just to comply with the GroupManager interface (it does nothing)
|
// Stop is a function created just to comply with the GroupManager interface (it does nothing)
|
||||||
|
@ -2,28 +2,29 @@ package keystore
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
|
"github.com/waku-org/go-waku/waku/v2/hash"
|
||||||
"github.com/waku-org/go-zerokit-rln/rln"
|
"github.com/waku-org/go-zerokit-rln/rln"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultCredentialsFilename is the default filename for the rln credentials keystore
|
// DefaultCredentialsFilename is the suggested default filename for the rln credentials keystore
|
||||||
const DefaultCredentialsFilename = "rlnKeystore.json"
|
const DefaultCredentialsFilename = "./rlnKeystore.json"
|
||||||
|
|
||||||
// DefaultCredentialsPassword contains the default password used when no password is specified
|
// DefaultCredentialsPassword is the suggested default password for the rln credentials store
|
||||||
const DefaultCredentialsPassword = "password"
|
const DefaultCredentialsPassword = "password"
|
||||||
|
|
||||||
// New creates a new instance of a rln credentials keystore
|
// New creates a new instance of a rln credentials keystore
|
||||||
func New(keystorePath string, appInfo AppInfo, logger *zap.Logger) (*AppKeystore, error) {
|
func New(path string, appInfo AppInfo, logger *zap.Logger) (*AppKeystore, error) {
|
||||||
logger = logger.Named("rln-keystore")
|
logger = logger.Named("rln-keystore")
|
||||||
|
|
||||||
path := keystorePath
|
|
||||||
if path == "" {
|
if path == "" {
|
||||||
logger.Warn("keystore: no credentials path set, using default path", zap.String("path", DefaultCredentialsFilename))
|
logger.Warn("keystore: no credentials path set, using default path", zap.String("path", DefaultCredentialsFilename))
|
||||||
path = DefaultCredentialsFilename
|
path = DefaultCredentialsFilename
|
||||||
@ -53,13 +54,18 @@ func New(keystorePath string, appInfo AppInfo, logger *zap.Logger) (*AppKeystore
|
|||||||
}
|
}
|
||||||
|
|
||||||
keystore := new(AppKeystore)
|
keystore := new(AppKeystore)
|
||||||
keystore.logger = logger
|
|
||||||
keystore.path = path
|
|
||||||
err := json.Unmarshal(keystoreBytes, keystore)
|
err := json.Unmarshal(keystoreBytes, keystore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keystore.logger = logger
|
||||||
|
keystore.path = path
|
||||||
|
|
||||||
|
if keystore.Credentials == nil {
|
||||||
|
keystore.Credentials = map[Key]appKeystoreCredential{}
|
||||||
|
}
|
||||||
|
|
||||||
if keystore.AppIdentifier == appInfo.AppIdentifier && keystore.Application == appInfo.Application && keystore.Version == appInfo.Version {
|
if keystore.AppIdentifier == appInfo.AppIdentifier && keystore.Application == appInfo.Application && keystore.Version == appInfo.Version {
|
||||||
return keystore, nil
|
return keystore, nil
|
||||||
}
|
}
|
||||||
@ -68,128 +74,67 @@ func New(keystorePath string, appInfo AppInfo, logger *zap.Logger) (*AppKeystore
|
|||||||
return nil, errors.New("no keystore found")
|
return nil, errors.New("no keystore found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getKey(treeIndex rln.MembershipIndex, filterMembershipContract MembershipContractInfo) (Key, error) {
|
||||||
|
keyStr := fmt.Sprintf("%s%s%d", filterMembershipContract.ChainID, filterMembershipContract.Address, treeIndex)
|
||||||
|
hash := hash.SHA256([]byte(keyStr))
|
||||||
|
return Key(strings.ToUpper(hex.EncodeToString(hash))), nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetMembershipCredentials decrypts and retrieves membership credentials from the keystore applying filters
|
// GetMembershipCredentials decrypts and retrieves membership credentials from the keystore applying filters
|
||||||
func (k *AppKeystore) GetMembershipCredentials(keystorePassword string, filterIdentityCredentials []MembershipCredentials, filterMembershipContracts []MembershipContract) ([]MembershipCredentials, error) {
|
func (k *AppKeystore) GetMembershipCredentials(keystorePassword string, treeIndex rln.MembershipIndex, filterMembershipContract MembershipContractInfo) (*MembershipCredentials, error) {
|
||||||
password := keystorePassword
|
key, err := getKey(treeIndex, filterMembershipContract)
|
||||||
if password == "" {
|
if err != nil {
|
||||||
k.logger.Warn("keystore: no credentials password set, using default password", zap.String("password", DefaultCredentialsPassword))
|
return nil, err
|
||||||
password = DefaultCredentialsPassword
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var result []MembershipCredentials
|
credential, ok := k.Credentials[key]
|
||||||
|
if !ok {
|
||||||
for _, credential := range k.Credentials {
|
return nil, nil
|
||||||
credentialsBytes, err := keystore.DecryptDataV3(credential.Crypto, password)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var credentials MembershipCredentials
|
|
||||||
err = json.Unmarshal(credentialsBytes, &credentials)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
filteredCredential := filterCredential(credentials, filterIdentityCredentials, filterMembershipContracts)
|
|
||||||
if filteredCredential != nil {
|
|
||||||
result = append(result, *filteredCredential)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
credentialsBytes, err := keystore.DecryptDataV3(credential.Crypto, keystorePassword)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
credentials := new(MembershipCredentials)
|
||||||
|
err = json.Unmarshal(credentialsBytes, credentials)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return credentials, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddMembershipCredentials inserts a membership credential to the keystore matching the application, appIdentifier and version filters.
|
// AddMembershipCredentials inserts a membership credential to the keystore matching the application, appIdentifier and version filters.
|
||||||
func (k *AppKeystore) AddMembershipCredentials(newIdentityCredential *rln.IdentityCredential, newMembershipGroup MembershipGroup, password string) (membershipGroupIndex uint, err error) {
|
func (k *AppKeystore) AddMembershipCredentials(newCredential MembershipCredentials, password string) error {
|
||||||
// A flag to tell us if the keystore contains a credential associated to the input identity credential, i.e. membershipCredential
|
credentials, err := k.GetMembershipCredentials(password, newCredential.TreeIndex, newCredential.MembershipContractInfo)
|
||||||
found := false
|
if err != nil {
|
||||||
for i, existingCredentials := range k.Credentials {
|
return err
|
||||||
credentialsBytes, err := keystore.DecryptDataV3(existingCredentials.Crypto, password)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var credentials MembershipCredentials
|
|
||||||
err = json.Unmarshal(credentialsBytes, &credentials)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if rln.IdentityCredentialEquals(*credentials.IdentityCredential, *newIdentityCredential) {
|
|
||||||
// idCredential is present in keystore. We add the input credential membership group to the one contained in the decrypted keystore credential (we deduplicate groups using sets)
|
|
||||||
allMembershipsMap := make(map[MembershipGroup]struct{})
|
|
||||||
for _, m := range credentials.MembershipGroups {
|
|
||||||
allMembershipsMap[m] = struct{}{}
|
|
||||||
}
|
|
||||||
allMembershipsMap[newMembershipGroup] = struct{}{}
|
|
||||||
|
|
||||||
// We sort membership groups, otherwise we will not have deterministic results in tests
|
|
||||||
var allMemberships []MembershipGroup
|
|
||||||
for k := range allMembershipsMap {
|
|
||||||
allMemberships = append(allMemberships, k)
|
|
||||||
}
|
|
||||||
sort.Slice(allMemberships, func(i, j int) bool {
|
|
||||||
return allMemberships[i].MembershipContract.Address < allMemberships[j].MembershipContract.Address
|
|
||||||
})
|
|
||||||
|
|
||||||
// we define the updated credential with the updated membership sets
|
|
||||||
updatedCredential := MembershipCredentials{
|
|
||||||
IdentityCredential: newIdentityCredential,
|
|
||||||
MembershipGroups: allMemberships,
|
|
||||||
}
|
|
||||||
|
|
||||||
// we re-encrypt creating a new keyfile
|
|
||||||
b, err := json.Marshal(updatedCredential)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
encryptedCredentials, err := keystore.EncryptDataV3(b, []byte(password), keystore.StandardScryptN, keystore.StandardScryptP)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// we update the original credential field in keystoreCredentials
|
|
||||||
k.Credentials[i] = appKeystoreCredential{Crypto: encryptedCredentials}
|
|
||||||
|
|
||||||
found = true
|
|
||||||
|
|
||||||
// We setup the return values
|
|
||||||
membershipGroupIndex = uint(len(allMemberships))
|
|
||||||
for mIdx, mg := range updatedCredential.MembershipGroups {
|
|
||||||
if mg.MembershipContract.Equals(newMembershipGroup.MembershipContract) {
|
|
||||||
membershipGroupIndex = uint(mIdx)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We stop decrypting other credentials in the keystore
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !found { // Not found
|
key, err := getKey(newCredential.TreeIndex, newCredential.MembershipContractInfo)
|
||||||
newCredential := MembershipCredentials{
|
if err != nil {
|
||||||
IdentityCredential: newIdentityCredential,
|
return err
|
||||||
MembershipGroups: []MembershipGroup{newMembershipGroup},
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := json.Marshal(newCredential)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
encryptedCredentials, err := keystore.EncryptDataV3(b, []byte(password), keystore.StandardScryptN, keystore.StandardScryptP)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k.Credentials = append(k.Credentials, appKeystoreCredential{Crypto: encryptedCredentials})
|
|
||||||
|
|
||||||
membershipGroupIndex = uint(len(newCredential.MembershipGroups) - 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return membershipGroupIndex, save(k, k.path)
|
if credentials != nil {
|
||||||
|
return errors.New("credential already present")
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := json.Marshal(newCredential)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptedCredentials, err := keystore.EncryptDataV3(b, []byte(password), keystore.StandardScryptN, keystore.StandardScryptP)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
k.Credentials[key] = appKeystoreCredential{Crypto: encryptedCredentials}
|
||||||
|
|
||||||
|
return save(k, k.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createAppKeystore(path string, appInfo AppInfo, separator string) error {
|
func createAppKeystore(path string, appInfo AppInfo, separator string) error {
|
||||||
@ -201,6 +146,7 @@ func createAppKeystore(path string, appInfo AppInfo, separator string) error {
|
|||||||
Application: appInfo.Application,
|
Application: appInfo.Application,
|
||||||
AppIdentifier: appInfo.AppIdentifier,
|
AppIdentifier: appInfo.AppIdentifier,
|
||||||
Version: appInfo.Version,
|
Version: appInfo.Version,
|
||||||
|
Credentials: make(map[Key]appKeystoreCredential),
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := json.Marshal(keystore)
|
b, err := json.Marshal(keystore)
|
||||||
@ -220,46 +166,6 @@ func createAppKeystore(path string, appInfo AppInfo, separator string) error {
|
|||||||
return os.WriteFile(path, buffer.Bytes(), 0600)
|
return os.WriteFile(path, buffer.Bytes(), 0600)
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterCredential(credential MembershipCredentials, filterIdentityCredentials []MembershipCredentials, filterMembershipContracts []MembershipContract) *MembershipCredentials {
|
|
||||||
if len(filterIdentityCredentials) != 0 {
|
|
||||||
found := false
|
|
||||||
for _, filterCreds := range filterIdentityCredentials {
|
|
||||||
if filterCreds.Equals(credential) {
|
|
||||||
found = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(filterMembershipContracts) != 0 {
|
|
||||||
var membershipGroupsIntersection []MembershipGroup
|
|
||||||
for _, filterContract := range filterMembershipContracts {
|
|
||||||
for _, credentialGroups := range credential.MembershipGroups {
|
|
||||||
if filterContract.Equals(credentialGroups.MembershipContract) {
|
|
||||||
membershipGroupsIntersection = append(membershipGroupsIntersection, credentialGroups)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(membershipGroupsIntersection) != 0 {
|
|
||||||
// If we have a match on some groups, we return the credential with filtered groups
|
|
||||||
return &MembershipCredentials{
|
|
||||||
IdentityCredential: credential.IdentityCredential,
|
|
||||||
MembershipGroups: membershipGroupsIntersection,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We hit this return only if
|
|
||||||
// - filterIdentityCredentials.len() == 0 and filterMembershipContracts.len() == 0 (no filter)
|
|
||||||
// - filterIdentityCredentials.len() != 0 and filterMembershipContracts.len() == 0 (filter only on identity credential)
|
|
||||||
// Indeed, filterMembershipContracts.len() != 0 will have its exclusive return based on all values of membershipGroupsIntersection.len()
|
|
||||||
return &credential
|
|
||||||
}
|
|
||||||
|
|
||||||
// Safely saves a Keystore's JsonNode to disk.
|
// Safely saves a Keystore's JsonNode to disk.
|
||||||
// If exists, the destination file is renamed with extension .bkp; the file is written at its destination and the .bkp file is removed if write is successful, otherwise is restored
|
// If exists, the destination file is renamed with extension .bkp; the file is written at its destination and the .bkp file is removed if write is successful, otherwise is restored
|
||||||
func save(keystore *AppKeystore, path string) error {
|
func save(keystore *AppKeystore, path string) error {
|
||||||
|
@ -1,59 +1,93 @@
|
|||||||
package keystore
|
package keystore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/waku-org/go-zerokit-rln/rln"
|
"github.com/waku-org/go-zerokit-rln/rln"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MembershipContract contains information about a membership smart contract address and the chain in which it is deployed
|
// MembershipContractInfo contains information about a membership smart contract address and the chain in which it is deployed
|
||||||
type MembershipContract struct {
|
type MembershipContractInfo struct {
|
||||||
ChainID string `json:"chainId"`
|
ChainID ChainID `json:"chainId"`
|
||||||
Address string `json:"address"`
|
Address ContractAddress `json:"address"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMembershipContractInfo generates a new MembershipContract instance
|
||||||
|
func NewMembershipContractInfo(chainID *big.Int, address common.Address) MembershipContractInfo {
|
||||||
|
return MembershipContractInfo{
|
||||||
|
ChainID: ChainID{
|
||||||
|
chainID,
|
||||||
|
},
|
||||||
|
Address: ContractAddress(address),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContractAddress is a common.Address created to comply with the expected marshalling for the credentials
|
||||||
|
type ContractAddress common.Address
|
||||||
|
|
||||||
|
// MarshalText is used to convert a ContractAddress into a valid value expected by the json encoder
|
||||||
|
func (c ContractAddress) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(common.Address(c).Hex()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText converts a byte slice into a ContractAddress
|
||||||
|
func (c *ContractAddress) UnmarshalText(text []byte) error {
|
||||||
|
b, err := hexutil.Decode(string(text))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
copy(c[:], b[:])
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChainID is a helper struct created to comply with the expected marshalling for the credentials
|
||||||
|
type ChainID struct {
|
||||||
|
*big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string with the expected chainId format for the credentials
|
||||||
|
func (c ChainID) String() string {
|
||||||
|
return fmt.Sprintf(`"%s"`, hexutil.EncodeBig(c.Int))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON is used to convert a ChainID into a valid value expected by the json encoder
|
||||||
|
func (c ChainID) MarshalJSON() (text []byte, err error) {
|
||||||
|
return []byte(c.String()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON converts a byte slice into a ChainID
|
||||||
|
func (c *ChainID) UnmarshalJSON(text []byte) error {
|
||||||
|
hexVal := strings.ReplaceAll(string(text), `"`, "")
|
||||||
|
b, err := hexutil.DecodeBig(hexVal)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Int = b
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equals is used to compare MembershipContract
|
// Equals is used to compare MembershipContract
|
||||||
func (m MembershipContract) Equals(other MembershipContract) bool {
|
func (m MembershipContractInfo) Equals(other MembershipContractInfo) bool {
|
||||||
return m.Address == other.Address && m.ChainID == other.ChainID
|
return m.Address == other.Address && m.ChainID.Int64() == other.ChainID.Int64()
|
||||||
}
|
|
||||||
|
|
||||||
// MembershipGroup contains information about the index in which a credential is stored in the merkle tree and the contract associated to this credential
|
|
||||||
type MembershipGroup struct {
|
|
||||||
MembershipContract MembershipContract `json:"membershipContract"`
|
|
||||||
TreeIndex rln.MembershipIndex `json:"treeIndex"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equals is used to compare MembershipGroup
|
|
||||||
func (m MembershipGroup) Equals(other MembershipGroup) bool {
|
|
||||||
return m.MembershipContract.Equals(other.MembershipContract) && m.TreeIndex == other.TreeIndex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MembershipCredentials contains all the information about an RLN Identity Credential and membership group it belongs to
|
// MembershipCredentials contains all the information about an RLN Identity Credential and membership group it belongs to
|
||||||
type MembershipCredentials struct {
|
type MembershipCredentials struct {
|
||||||
IdentityCredential *rln.IdentityCredential `json:"identityCredential"`
|
IdentityCredential *rln.IdentityCredential `json:"identityCredential"`
|
||||||
MembershipGroups []MembershipGroup `json:"membershipGroups"`
|
MembershipContractInfo MembershipContractInfo `json:"membershipContract"`
|
||||||
|
TreeIndex rln.MembershipIndex `json:"treeIndex"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equals is used to compare MembershipCredentials
|
// Equals is used to compare MembershipCredentials
|
||||||
func (m MembershipCredentials) Equals(other MembershipCredentials) bool {
|
func (m MembershipCredentials) Equals(other MembershipCredentials) bool {
|
||||||
if !rln.IdentityCredentialEquals(*m.IdentityCredential, *other.IdentityCredential) {
|
return rln.IdentityCredentialEquals(*m.IdentityCredential, *other.IdentityCredential) && m.MembershipContractInfo.Equals(other.MembershipContractInfo) && m.TreeIndex == other.TreeIndex
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, x := range m.MembershipGroups {
|
|
||||||
found := false
|
|
||||||
for _, y := range other.MembershipGroups {
|
|
||||||
if x.Equals(y) {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppInfo is a helper structure that contains information about the application that uses these credentials
|
// AppInfo is a helper structure that contains information about the application that uses these credentials
|
||||||
@ -63,12 +97,15 @@ type AppInfo struct {
|
|||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Key is a helper type created to represent the key in a map of credentials
|
||||||
|
type Key string
|
||||||
|
|
||||||
// AppKeystore represents the membership credentials to be used in RLN
|
// AppKeystore represents the membership credentials to be used in RLN
|
||||||
type AppKeystore struct {
|
type AppKeystore struct {
|
||||||
Application string `json:"application"`
|
Application string `json:"application"`
|
||||||
AppIdentifier string `json:"appIdentifier"`
|
AppIdentifier string `json:"appIdentifier"`
|
||||||
Credentials []appKeystoreCredential `json:"credentials"`
|
Credentials map[Key]appKeystoreCredential `json:"credentials"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
|
|
||||||
path string
|
path string
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
|
@ -6,7 +6,6 @@ package rln
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
@ -103,7 +102,7 @@ func (s *WakuRLNRelayDynamicSuite) generateCredentials(rlnInstance *rln.RLN) *rl
|
|||||||
return identityCredential
|
return identityCredential
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *WakuRLNRelayDynamicSuite) register(identityCredential *rln.IdentityCredential, privKey *ecdsa.PrivateKey, keystorePath string) (rln.MembershipIndex, uint) {
|
func (s *WakuRLNRelayDynamicSuite) register(appKeystore *keystore.AppKeystore, identityCredential *rln.IdentityCredential, privKey *ecdsa.PrivateKey) rln.MembershipIndex {
|
||||||
|
|
||||||
auth, err := bind.NewKeyedTransactorWithChainID(privKey, s.chainID)
|
auth, err := bind.NewKeyedTransactorWithChainID(privKey, s.chainID)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
@ -123,18 +122,16 @@ func (s *WakuRLNRelayDynamicSuite) register(identityCredential *rln.IdentityCred
|
|||||||
|
|
||||||
membershipIndex := rln.MembershipIndex(uint(evt.Index.Int64()))
|
membershipIndex := rln.MembershipIndex(uint(evt.Index.Int64()))
|
||||||
|
|
||||||
membershipGroup := keystore.MembershipGroup{
|
membershipCredential := keystore.MembershipCredentials{
|
||||||
TreeIndex: membershipIndex,
|
IdentityCredential: identityCredential,
|
||||||
MembershipContract: keystore.MembershipContract{
|
TreeIndex: membershipIndex,
|
||||||
ChainId: fmt.Sprintf("0x%X", s.chainID.Int64()),
|
MembershipContractInfo: keystore.NewMembershipContractInfo(s.chainID, s.rlnAddr),
|
||||||
Address: s.rlnAddr.String(),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
membershipGroupIndex, err := keystore.AddMembershipCredentials(keystorePath, identityCredential, membershipGroup, keystorePassword, dynamic.RLNAppInfo, keystore.DefaultSeparator)
|
err = appKeystore.AddMembershipCredentials(membershipCredential, keystorePassword)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
return membershipIndex, membershipGroupIndex
|
return membershipIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *WakuRLNRelayDynamicSuite) TestDynamicGroupManagement() {
|
func (s *WakuRLNRelayDynamicSuite) TestDynamicGroupManagement() {
|
||||||
@ -147,10 +144,13 @@ func (s *WakuRLNRelayDynamicSuite) TestDynamicGroupManagement() {
|
|||||||
|
|
||||||
u1Credentials := s.generateCredentials(rlnInstance)
|
u1Credentials := s.generateCredentials(rlnInstance)
|
||||||
keystorePath1 := "./test_onchain.json"
|
keystorePath1 := "./test_onchain.json"
|
||||||
_, membershipGroupIndex := s.register(u1Credentials, s.u1PrivKey, keystorePath1)
|
appKeystore, err := keystore.New(keystorePath1, dynamic.RLNAppInfo, utils.Logger())
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
membershipIndex := s.register(appKeystore, u1Credentials, s.u1PrivKey)
|
||||||
defer s.removeCredentials(keystorePath1)
|
defer s.removeCredentials(keystorePath1)
|
||||||
|
|
||||||
gm, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.rlnAddr, membershipGroupIndex, keystorePath1, keystorePassword, 0, false, prometheus.DefaultRegisterer, utils.Logger())
|
gm, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.rlnAddr, membershipIndex, appKeystore, keystorePassword, prometheus.DefaultRegisterer, utils.Logger())
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
// initialize the WakuRLNRelay
|
// initialize the WakuRLNRelay
|
||||||
@ -167,7 +167,10 @@ func (s *WakuRLNRelayDynamicSuite) TestDynamicGroupManagement() {
|
|||||||
|
|
||||||
u2Credentials := s.generateCredentials(rlnInstance)
|
u2Credentials := s.generateCredentials(rlnInstance)
|
||||||
keystorePath2 := "./test_onchain2.json"
|
keystorePath2 := "./test_onchain2.json"
|
||||||
membershipIndex, _ := s.register(u2Credentials, s.u2PrivKey, keystorePath2)
|
appKeystore2, err := keystore.New(keystorePath2, dynamic.RLNAppInfo, utils.Logger())
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
membershipIndex = s.register(appKeystore2, u2Credentials, s.u2PrivKey)
|
||||||
defer s.removeCredentials(keystorePath2)
|
defer s.removeCredentials(keystorePath2)
|
||||||
|
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
@ -187,7 +190,10 @@ func (s *WakuRLNRelayDynamicSuite) TestInsertKeyMembershipContract() {
|
|||||||
credentials3 := s.generateCredentials(rlnInstance)
|
credentials3 := s.generateCredentials(rlnInstance)
|
||||||
|
|
||||||
keystorePath1 := "./test_onchain.json"
|
keystorePath1 := "./test_onchain.json"
|
||||||
s.register(credentials1, s.u1PrivKey, keystorePath1)
|
appKeystore, err := keystore.New(keystorePath1, dynamic.RLNAppInfo, utils.Logger())
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
s.register(appKeystore, credentials1, s.u1PrivKey)
|
||||||
defer s.removeCredentials(keystorePath1)
|
defer s.removeCredentials(keystorePath1)
|
||||||
|
|
||||||
// Batch Register
|
// Batch Register
|
||||||
@ -224,14 +230,18 @@ func (s *WakuRLNRelayDynamicSuite) TestMerkleTreeConstruction() {
|
|||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
// register the members to the contract
|
// register the members to the contract
|
||||||
_, membershipGroupIndex := s.register(credentials1, s.u1PrivKey, "./test_onchain.json")
|
keystorePath1 := "./test_onchain.json"
|
||||||
_, membershipGroupIndex = s.register(credentials2, s.u1PrivKey, "./test_onchain.json")
|
appKeystore, err := keystore.New(keystorePath1, dynamic.RLNAppInfo, utils.Logger())
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
membershipIndex := s.register(appKeystore, credentials1, s.u1PrivKey)
|
||||||
|
membershipIndex = s.register(appKeystore, credentials2, s.u1PrivKey)
|
||||||
|
|
||||||
|
defer s.removeCredentials(keystorePath1)
|
||||||
|
|
||||||
// mount the rln relay protocol in the on-chain/dynamic mode
|
// mount the rln relay protocol in the on-chain/dynamic mode
|
||||||
// TODO: This assumes the keystoreIndex is 0, but there are two possible credentials in this keystore due to using the same contract address
|
gm, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.rlnAddr, membershipIndex, appKeystore, keystorePassword, prometheus.DefaultRegisterer, utils.Logger())
|
||||||
// when credentials1 and credentials2 were registered. We should remove this hardcoded value and obtain the correct value when the credentials are persisted
|
|
||||||
keystoreIndex := uint(0)
|
|
||||||
gm, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.rlnAddr, membershipGroupIndex, "./test_onchain.json", keystorePassword, keystoreIndex, false, prometheus.DefaultRegisterer, utils.Logger())
|
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
rlnRelay, err := New(gm, "test-merkle-tree.db", timesource.NewDefaultClock(), prometheus.DefaultRegisterer, utils.Logger())
|
rlnRelay, err := New(gm, "test-merkle-tree.db", timesource.NewDefaultClock(), prometheus.DefaultRegisterer, utils.Logger())
|
||||||
@ -261,11 +271,13 @@ func (s *WakuRLNRelayDynamicSuite) TestCorrectRegistrationOfPeers() {
|
|||||||
// Register credentials1 in contract and keystore1
|
// Register credentials1 in contract and keystore1
|
||||||
credentials1 := s.generateCredentials(rlnInstance)
|
credentials1 := s.generateCredentials(rlnInstance)
|
||||||
keystorePath1 := "./test_onchain.json"
|
keystorePath1 := "./test_onchain.json"
|
||||||
_, membershipGroupIndex := s.register(credentials1, s.u1PrivKey, keystorePath1)
|
appKeystore, err := keystore.New(keystorePath1, dynamic.RLNAppInfo, utils.Logger())
|
||||||
|
s.Require().NoError(err)
|
||||||
|
membershipGroupIndex := s.register(appKeystore, credentials1, s.u1PrivKey)
|
||||||
defer s.removeCredentials(keystorePath1)
|
defer s.removeCredentials(keystorePath1)
|
||||||
|
|
||||||
// mount the rln relay protocol in the on-chain/dynamic mode
|
// mount the rln relay protocol in the on-chain/dynamic mode
|
||||||
gm1, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.rlnAddr, membershipGroupIndex, keystorePath1, keystorePassword, 0, false, prometheus.DefaultRegisterer, utils.Logger())
|
gm1, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.rlnAddr, membershipGroupIndex, appKeystore, keystorePassword, prometheus.DefaultRegisterer, utils.Logger())
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
rlnRelay1, err := New(gm1, "test-correct-registration-1.db", timesource.NewDefaultClock(), prometheus.DefaultRegisterer, utils.Logger())
|
rlnRelay1, err := New(gm1, "test-correct-registration-1.db", timesource.NewDefaultClock(), prometheus.DefaultRegisterer, utils.Logger())
|
||||||
@ -278,11 +290,13 @@ func (s *WakuRLNRelayDynamicSuite) TestCorrectRegistrationOfPeers() {
|
|||||||
// Register credentials2 in contract and keystore2
|
// Register credentials2 in contract and keystore2
|
||||||
credentials2 := s.generateCredentials(rlnInstance)
|
credentials2 := s.generateCredentials(rlnInstance)
|
||||||
keystorePath2 := "./test_onchain2.json"
|
keystorePath2 := "./test_onchain2.json"
|
||||||
_, membershipGroupIndex = s.register(credentials2, s.u2PrivKey, keystorePath2)
|
appKeystore2, err := keystore.New(keystorePath2, dynamic.RLNAppInfo, utils.Logger())
|
||||||
|
s.Require().NoError(err)
|
||||||
|
membershipGroupIndex = s.register(appKeystore2, credentials2, s.u2PrivKey)
|
||||||
defer s.removeCredentials(keystorePath2)
|
defer s.removeCredentials(keystorePath2)
|
||||||
|
|
||||||
// mount the rln relay protocol in the on-chain/dynamic mode
|
// mount the rln relay protocol in the on-chain/dynamic mode
|
||||||
gm2, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.rlnAddr, membershipGroupIndex, keystorePath2, keystorePassword, 0, false, prometheus.DefaultRegisterer, utils.Logger())
|
gm2, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.rlnAddr, membershipGroupIndex, appKeystore2, keystorePassword, prometheus.DefaultRegisterer, utils.Logger())
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
rlnRelay2, err := New(gm2, "test-correct-registration-2.db", timesource.NewDefaultClock(), prometheus.DefaultRegisterer, utils.Logger())
|
rlnRelay2, err := New(gm2, "test-correct-registration-2.db", timesource.NewDefaultClock(), prometheus.DefaultRegisterer, utils.Logger())
|
||||||
@ -294,9 +308,8 @@ func (s *WakuRLNRelayDynamicSuite) TestCorrectRegistrationOfPeers() {
|
|||||||
// the two nodes should be registered into the contract
|
// the two nodes should be registered into the contract
|
||||||
// since nodes are spun up sequentially
|
// since nodes are spun up sequentially
|
||||||
// the first node has index 0 whereas the second node gets index 1
|
// the first node has index 0 whereas the second node gets index 1
|
||||||
idx1, err := rlnRelay1.groupManager.MembershipIndex()
|
idx1 := rlnRelay1.groupManager.MembershipIndex()
|
||||||
s.Require().NoError(err)
|
idx2 := rlnRelay2.groupManager.MembershipIndex()
|
||||||
idx2, err := rlnRelay2.groupManager.MembershipIndex()
|
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().Equal(rln.MembershipIndex(0), idx1)
|
s.Require().Equal(rln.MembershipIndex(0), idx1)
|
||||||
|
@ -25,7 +25,7 @@ import (
|
|||||||
type GroupManager interface {
|
type GroupManager interface {
|
||||||
Start(ctx context.Context, rln *rln.RLN, rootTracker *group_manager.MerkleRootTracker) error
|
Start(ctx context.Context, rln *rln.RLN, rootTracker *group_manager.MerkleRootTracker) error
|
||||||
IdentityCredentials() (rln.IdentityCredential, error)
|
IdentityCredentials() (rln.IdentityCredential, error)
|
||||||
MembershipIndex() (rln.MembershipIndex, error)
|
MembershipIndex() rln.MembershipIndex
|
||||||
Stop() error
|
Stop() error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,10 +356,7 @@ func (rlnRelay *WakuRLNRelay) generateProof(input []byte, epoch rln.Epoch) (*pb.
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
membershipIndex, err := rlnRelay.groupManager.MembershipIndex()
|
membershipIndex := rlnRelay.groupManager.MembershipIndex()
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
proof, err := rlnRelay.RLN.GenerateProof(input, identityCredentials, membershipIndex, epoch)
|
proof, err := rlnRelay.RLN.GenerateProof(input, identityCredentials, membershipIndex, epoch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -381,6 +378,6 @@ func (rlnRelay *WakuRLNRelay) IdentityCredential() (rln.IdentityCredential, erro
|
|||||||
return rlnRelay.groupManager.IdentityCredentials()
|
return rlnRelay.groupManager.IdentityCredentials()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rlnRelay *WakuRLNRelay) MembershipIndex() (uint, error) {
|
func (rlnRelay *WakuRLNRelay) MembershipIndex() uint {
|
||||||
return rlnRelay.groupManager.MembershipIndex()
|
return rlnRelay.groupManager.MembershipIndex()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user