mirror of https://github.com/status-im/go-waku.git
feat: use rln registry contract
This commit is contained in:
parent
ab3f21f209
commit
5fcfbb9897
|
@ -9,12 +9,11 @@ import (
|
|||
"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/protocol/rln/web3"
|
||||
"github.com/waku-org/go-waku/waku/v2/utils"
|
||||
"github.com/waku-org/go-zerokit-rln/rln"
|
||||
"go.uber.org/zap"
|
||||
|
@ -46,22 +45,12 @@ var Command = cli.Command{
|
|||
}
|
||||
|
||||
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)
|
||||
web3Config, err := web3.BuildConfig(ctx, options.ETHClientAddress, options.MembershipContractAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -74,14 +63,14 @@ func execute(ctx context.Context) error {
|
|||
}
|
||||
|
||||
// register the rln-relay peer to the membership contract
|
||||
membershipIndex, err := register(ctx, ethClient, rlnContract, identityCredential.IDCommitment, chainID)
|
||||
membershipIndex, err := register(ctx, web3Config, identityCredential.IDCommitment)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: clean private key from memory
|
||||
|
||||
err = persistCredentials(identityCredential, membershipIndex, chainID)
|
||||
err = persistCredentials(identityCredential, membershipIndex, web3Config.ChainID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -98,7 +87,7 @@ func execute(ctx context.Context) error {
|
|||
logger.Info("registered credentials into the membership contract", logging.HexString("idCommitment", identityCredential.IDCommitment[:]), zap.Uint("index", membershipIndex))
|
||||
}
|
||||
|
||||
ethClient.Close()
|
||||
web3Config.ETHClient.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -11,15 +11,14 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"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/web3"
|
||||
"github.com/waku-org/go-zerokit-rln/rln"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func getMembershipFee(ctx context.Context, rlnContract *contracts.RLN) (*big.Int, error) {
|
||||
func getMembershipFee(ctx context.Context, rlnContract web3.RLNContract) (*big.Int, error) {
|
||||
return rlnContract.MEMBERSHIPDEPOSIT(&bind.CallOpts{Context: ctx})
|
||||
}
|
||||
|
||||
|
@ -70,14 +69,14 @@ func buildTransactor(ctx context.Context, membershipFee *big.Int, chainID *big.I
|
|||
return auth, nil
|
||||
}
|
||||
|
||||
func register(ctx context.Context, ethClient *ethclient.Client, rlnContract *contracts.RLN, idComm rln.IDCommitment, chainID *big.Int) (rln.MembershipIndex, error) {
|
||||
func register(ctx context.Context, web3Config *web3.Config, idComm rln.IDCommitment) (rln.MembershipIndex, error) {
|
||||
// check if the contract exists by calling a static function
|
||||
membershipFee, err := getMembershipFee(ctx, rlnContract)
|
||||
membershipFee, err := getMembershipFee(ctx, web3Config.RLNContract)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
auth, err := buildTransactor(ctx, membershipFee, chainID)
|
||||
auth, err := buildTransactor(ctx, membershipFee, web3Config.ChainID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -85,13 +84,13 @@ func register(ctx context.Context, ethClient *ethclient.Client, rlnContract *con
|
|||
log.Debug("registering an id commitment", zap.Binary("idComm", idComm[:]))
|
||||
|
||||
// registers the idComm into the membership contract whose address is in rlnPeer.membershipContractAddress
|
||||
tx, err := rlnContract.Register(auth, rln.Bytes32ToBigInt(idComm))
|
||||
tx, err := web3Config.RegistryContract.Register(auth, web3Config.RLNContract.StorageIndex, rln.Bytes32ToBigInt(idComm))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("transaction error: %w", err)
|
||||
}
|
||||
|
||||
explorerURL := ""
|
||||
switch chainID.Int64() {
|
||||
switch web3Config.ChainID.Int64() {
|
||||
case 1:
|
||||
explorerURL = "https://etherscan.io"
|
||||
case 5:
|
||||
|
@ -108,7 +107,7 @@ func register(ctx context.Context, ethClient *ethclient.Client, rlnContract *con
|
|||
|
||||
logger.Warn("waiting for transaction to be mined...")
|
||||
|
||||
txReceipt, err := bind.WaitMined(ctx, ethClient, tx)
|
||||
txReceipt, err := bind.WaitMined(ctx, web3Config.ETHClient, tx)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("transaction error: %w", err)
|
||||
}
|
||||
|
@ -118,7 +117,7 @@ func register(ctx context.Context, ethClient *ethclient.Client, rlnContract *con
|
|||
}
|
||||
|
||||
// the receipt topic holds the hash of signature of the raised events
|
||||
evt, err := rlnContract.ParseMemberRegistered(*txReceipt.Logs[0])
|
||||
evt, err := web3Config.RLNContract.ParseMemberRegistered(*txReceipt.Logs[0])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
|
@ -10,12 +10,12 @@ import (
|
|||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"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"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol/rln/keystore"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol/rln/web3"
|
||||
"github.com/waku-org/go-zerokit-rln/rln"
|
||||
om "github.com/wk8/go-ordered-map"
|
||||
"go.uber.org/zap"
|
||||
|
@ -38,17 +38,11 @@ type DynamicGroupManager struct {
|
|||
identityCredential *rln.IdentityCredential
|
||||
membershipIndex rln.MembershipIndex
|
||||
|
||||
membershipContractAddress common.Address
|
||||
ethClientAddress string
|
||||
ethClient *ethclient.Client
|
||||
|
||||
web3Config *web3.Config
|
||||
lastBlockProcessed uint64
|
||||
|
||||
eventHandler RegistrationEventHandler
|
||||
|
||||
chainId *big.Int
|
||||
rlnContract *contracts.RLN
|
||||
|
||||
appKeystore *keystore.AppKeystore
|
||||
keystorePassword string
|
||||
|
||||
|
@ -99,14 +93,14 @@ func handler(gm *DynamicGroupManager, events []*contracts.RLNMemberRegistered) e
|
|||
gm.lastBlockProcessed = lastBlockProcessed
|
||||
err = gm.SetMetadata(RLNMetadata{
|
||||
LastProcessedBlock: gm.lastBlockProcessed,
|
||||
ChainID: gm.chainId,
|
||||
ContractAddress: gm.membershipContractAddress,
|
||||
ChainID: gm.web3Config.ChainID,
|
||||
ContractAddress: gm.web3Config.RegistryContract.Address,
|
||||
})
|
||||
if err != nil {
|
||||
// this is not a fatal error, hence we don't raise an exception
|
||||
gm.log.Warn("failed to persist rln metadata", zap.Error(err))
|
||||
} else {
|
||||
gm.log.Debug("rln metadata persisted", zap.Uint64("lastProcessedBlock", gm.lastBlockProcessed), zap.Uint64("chainID", gm.chainId.Uint64()), logging.HexBytes("contractAddress", gm.membershipContractAddress[:]))
|
||||
gm.log.Debug("rln metadata persisted", zap.Uint64("lastProcessedBlock", gm.lastBlockProcessed), zap.Uint64("chainID", gm.web3Config.ChainID.Uint64()), logging.HexBytes("contractAddress", gm.web3Config.RegistryContract.Address.Bytes()))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -127,8 +121,7 @@ func NewDynamicGroupManager(
|
|||
|
||||
return &DynamicGroupManager{
|
||||
membershipIndex: membershipIndex,
|
||||
membershipContractAddress: memContractAddr,
|
||||
ethClientAddress: ethClientAddr,
|
||||
web3Config: web3.NewConfig(ethClientAddr, memContractAddr),
|
||||
eventHandler: handler,
|
||||
appKeystore: appKeystore,
|
||||
keystorePassword: keystorePassword,
|
||||
|
@ -138,7 +131,7 @@ func NewDynamicGroupManager(
|
|||
}
|
||||
|
||||
func (gm *DynamicGroupManager) getMembershipFee(ctx context.Context) (*big.Int, error) {
|
||||
return gm.rlnContract.MEMBERSHIPDEPOSIT(&bind.CallOpts{Context: ctx})
|
||||
return gm.web3Config.RLNContract.MEMBERSHIPDEPOSIT(&bind.CallOpts{Context: ctx})
|
||||
}
|
||||
|
||||
func (gm *DynamicGroupManager) Start(ctx context.Context, rlnInstance *rln.RLN, rootTracker *group_manager.MerkleRootTracker) error {
|
||||
|
@ -151,25 +144,14 @@ func (gm *DynamicGroupManager) Start(ctx context.Context, rlnInstance *rln.RLN,
|
|||
|
||||
gm.log.Info("mounting rln-relay in on-chain/dynamic mode")
|
||||
|
||||
backend, err := ethclient.Dial(gm.ethClientAddress)
|
||||
err := gm.web3Config.Build(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gm.ethClient = backend
|
||||
|
||||
gm.rln = rlnInstance
|
||||
gm.rootTracker = rootTracker
|
||||
|
||||
gm.chainId, err = backend.ChainID(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gm.rlnContract, err = contracts.NewRLN(gm.membershipContractAddress, backend)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if the contract exists by calling a static function
|
||||
_, err = gm.getMembershipFee(ctx)
|
||||
if err != nil {
|
||||
|
@ -194,7 +176,7 @@ func (gm *DynamicGroupManager) loadCredential() error {
|
|||
credentials, err := gm.appKeystore.GetMembershipCredentials(
|
||||
gm.keystorePassword,
|
||||
gm.membershipIndex,
|
||||
keystore.NewMembershipContractInfo(gm.chainId, gm.membershipContractAddress))
|
||||
keystore.NewMembershipContractInfo(gm.web3Config.ChainID, gm.web3Config.RegistryContract.Address))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -281,7 +263,8 @@ func (gm *DynamicGroupManager) Stop() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gm.ethClient.Close()
|
||||
|
||||
gm.web3Config.ETHClient.Close()
|
||||
|
||||
gm.wg.Wait()
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol/rln/contracts"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol/rln/group_manager"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol/rln/web3"
|
||||
"github.com/waku-org/go-waku/waku/v2/utils"
|
||||
"github.com/waku-org/go-zerokit-rln/rln"
|
||||
)
|
||||
|
@ -44,7 +45,9 @@ func TestHandler(t *testing.T) {
|
|||
log: utils.Logger(),
|
||||
cancel: cancel,
|
||||
wg: sync.WaitGroup{},
|
||||
chainId: big.NewInt(1),
|
||||
web3Config: &web3.Config{
|
||||
ChainID: big.NewInt(1),
|
||||
},
|
||||
rootTracker: rootTracker,
|
||||
metrics: newMetrics(prometheus.DefaultRegisterer),
|
||||
}
|
||||
|
|
|
@ -26,11 +26,11 @@ func (gm *DynamicGroupManager) HandleGroupUpdates(ctx context.Context, handler R
|
|||
if err != nil {
|
||||
gm.log.Warn("could not load last processed block from metadata. Starting onchain sync from scratch", zap.Error(err))
|
||||
} else {
|
||||
if gm.chainId.Uint64() != metadata.ChainID.Uint64() {
|
||||
if gm.web3Config.ChainID.Cmp(metadata.ChainID) != 0 {
|
||||
return errors.New("persisted data: chain id mismatch")
|
||||
}
|
||||
|
||||
if !bytes.Equal(gm.membershipContractAddress[:], metadata.ContractAddress[:]) {
|
||||
if !bytes.Equal(gm.web3Config.RegistryContract.Address.Bytes(), metadata.ContractAddress.Bytes()) {
|
||||
return errors.New("persisted data: contract address mismatch")
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ func (gm *DynamicGroupManager) HandleGroupUpdates(ctx context.Context, handler R
|
|||
gm.log.Info("resuming onchain sync", zap.Uint64("fromBlock", fromBlock))
|
||||
}
|
||||
|
||||
err = gm.loadOldEvents(ctx, gm.rlnContract, fromBlock, handler)
|
||||
err = gm.loadOldEvents(ctx, fromBlock, handler)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -46,11 +46,11 @@ func (gm *DynamicGroupManager) HandleGroupUpdates(ctx context.Context, handler R
|
|||
errCh := make(chan error)
|
||||
|
||||
gm.wg.Add(1)
|
||||
go gm.watchNewEvents(ctx, gm.rlnContract, handler, gm.log, errCh)
|
||||
go gm.watchNewEvents(ctx, handler, gm.log, errCh)
|
||||
return <-errCh
|
||||
}
|
||||
|
||||
func (gm *DynamicGroupManager) loadOldEvents(ctx context.Context, rlnContract *contracts.RLN, fromBlock uint64, handler RegistrationEventHandler) error {
|
||||
func (gm *DynamicGroupManager) loadOldEvents(ctx context.Context, fromBlock uint64, handler RegistrationEventHandler) error {
|
||||
events, err := gm.getEvents(ctx, fromBlock, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -58,14 +58,14 @@ func (gm *DynamicGroupManager) loadOldEvents(ctx context.Context, rlnContract *c
|
|||
return handler(gm, events)
|
||||
}
|
||||
|
||||
func (gm *DynamicGroupManager) watchNewEvents(ctx context.Context, rlnContract *contracts.RLN, handler RegistrationEventHandler, log *zap.Logger, errCh chan<- error) {
|
||||
func (gm *DynamicGroupManager) watchNewEvents(ctx context.Context, handler RegistrationEventHandler, log *zap.Logger, errCh chan<- error) {
|
||||
defer gm.wg.Done()
|
||||
|
||||
// Watch for new events
|
||||
firstErr := true
|
||||
headerCh := make(chan *types.Header)
|
||||
subs := event.Resubscribe(2*time.Second, func(ctx context.Context) (event.Subscription, error) {
|
||||
s, err := gm.ethClient.SubscribeNewHead(ctx, headerCh)
|
||||
s, err := gm.web3Config.ETHClient.SubscribeNewHead(ctx, headerCh)
|
||||
if err != nil {
|
||||
if err == rpc.ErrNotificationsUnsupported {
|
||||
err = errors.New("notifications not supported. The node must support websockets")
|
||||
|
@ -123,7 +123,7 @@ func (gm *DynamicGroupManager) getEvents(ctx context.Context, from uint64, to *u
|
|||
|
||||
toBlock := to
|
||||
if to == nil {
|
||||
block, err := gm.ethClient.BlockByNumber(ctx, nil)
|
||||
block, err := gm.web3Config.ETHClient.BlockByNumber(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ func (gm *DynamicGroupManager) getEvents(ctx context.Context, from uint64, to *u
|
|||
}
|
||||
|
||||
func (gm *DynamicGroupManager) fetchEvents(ctx context.Context, from uint64, to *uint64) ([]*contracts.RLNMemberRegistered, error) {
|
||||
logIterator, err := gm.rlnContract.FilterMemberRegistered(&bind.FilterOpts{Start: from, End: to, Context: ctx})
|
||||
logIterator, err := gm.web3Config.RLNContract.FilterMemberRegistered(&bind.FilterOpts{Start: from, End: to, Context: ctx})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -6,14 +6,16 @@ package rln
|
|||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/waku-org/go-zerokit-rln/rln"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
@ -25,11 +27,11 @@ import (
|
|||
"github.com/waku-org/go-waku/waku/v2/protocol/rln/group_manager"
|
||||
"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/protocol/rln/web3"
|
||||
"github.com/waku-org/go-waku/waku/v2/timesource"
|
||||
"github.com/waku-org/go-waku/waku/v2/utils"
|
||||
)
|
||||
|
||||
var membershipFee = big.NewInt(1000000000000000) // wei - 0.001 eth
|
||||
const keystorePassword = "test"
|
||||
|
||||
func TestWakuRLNRelayDynamicSuite(t *testing.T) {
|
||||
|
@ -38,29 +40,27 @@ func TestWakuRLNRelayDynamicSuite(t *testing.T) {
|
|||
|
||||
type WakuRLNRelayDynamicSuite struct {
|
||||
suite.Suite
|
||||
|
||||
clientAddr string
|
||||
|
||||
backend *ethclient.Client
|
||||
chainID *big.Int
|
||||
rlnAddr common.Address
|
||||
rlnContract *contracts.RLN
|
||||
|
||||
web3Config *web3.Config
|
||||
u1PrivKey *ecdsa.PrivateKey
|
||||
u2PrivKey *ecdsa.PrivateKey
|
||||
}
|
||||
|
||||
// TODO: on teardown, remove credentials
|
||||
func TempFileName(prefix, suffix string) string {
|
||||
randBytes := make([]byte, 16)
|
||||
rand.Read(randBytes)
|
||||
return filepath.Join(os.TempDir(), prefix+hex.EncodeToString(randBytes)+suffix)
|
||||
}
|
||||
|
||||
func (s *WakuRLNRelayDynamicSuite) SetupTest() {
|
||||
|
||||
s.clientAddr = os.Getenv("GANACHE_NETWORK_RPC_URL")
|
||||
if s.clientAddr == "" {
|
||||
s.clientAddr = "ws://localhost:8545"
|
||||
clientAddr := os.Getenv("GANACHE_NETWORK_RPC_URL")
|
||||
if clientAddr == "" {
|
||||
clientAddr = "ws://localhost:8545"
|
||||
}
|
||||
|
||||
backend, err := ethclient.Dial(s.clientAddr)
|
||||
backend, err := ethclient.Dial(clientAddr)
|
||||
s.Require().NoError(err)
|
||||
defer backend.Close()
|
||||
|
||||
chainID, err := backend.ChainID(context.TODO())
|
||||
s.Require().NoError(err)
|
||||
|
@ -72,9 +72,6 @@ func (s *WakuRLNRelayDynamicSuite) SetupTest() {
|
|||
s.u2PrivKey, err = crypto.ToECDSA(common.FromHex("0xa00da43843ad6b5161ddbace48f293ac3f82f8a8257af34de4c32900bb6e9a97"))
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.backend = backend
|
||||
s.chainID = chainID
|
||||
|
||||
// Deploying contracts
|
||||
auth, err := bind.NewKeyedTransactorWithChainID(s.u1PrivKey, chainID)
|
||||
s.Require().NoError(err)
|
||||
|
@ -82,18 +79,21 @@ func (s *WakuRLNRelayDynamicSuite) SetupTest() {
|
|||
poseidonHasherAddr, _, _, err := contracts.DeployPoseidonHasher(auth, backend)
|
||||
s.Require().NoError(err)
|
||||
|
||||
rlnAddr, _, rlnContract, err := contracts.DeployRLN(auth, backend, membershipFee, big.NewInt(20), poseidonHasherAddr)
|
||||
registryAddress, tx, rlnRegistry, err := contracts.DeployRLNRegistry(auth, backend, poseidonHasherAddr)
|
||||
s.Require().NoError(err)
|
||||
txReceipt, err := bind.WaitMined(context.TODO(), backend, tx)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(txReceipt.Status, types.ReceiptStatusSuccessful)
|
||||
|
||||
s.rlnAddr = rlnAddr
|
||||
s.rlnContract = rlnContract
|
||||
}
|
||||
tx, err = rlnRegistry.NewStorage(auth)
|
||||
s.Require().NoError(err)
|
||||
txReceipt, err = bind.WaitMined(context.TODO(), backend, tx)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(txReceipt.Status, types.ReceiptStatusSuccessful)
|
||||
|
||||
func (s *WakuRLNRelayDynamicSuite) removeCredentials(path string) {
|
||||
err := os.Remove(path)
|
||||
if err != nil {
|
||||
utils.Logger().Warn("could not remove credentials", zap.String("path", path))
|
||||
}
|
||||
s.web3Config = web3.NewConfig(clientAddr, registryAddress)
|
||||
err = s.web3Config.Build(context.TODO())
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
func (s *WakuRLNRelayDynamicSuite) generateCredentials(rlnInstance *rln.RLN) *rln.IdentityCredential {
|
||||
|
@ -103,21 +103,22 @@ func (s *WakuRLNRelayDynamicSuite) generateCredentials(rlnInstance *rln.RLN) *rl
|
|||
}
|
||||
|
||||
func (s *WakuRLNRelayDynamicSuite) register(appKeystore *keystore.AppKeystore, identityCredential *rln.IdentityCredential, privKey *ecdsa.PrivateKey) rln.MembershipIndex {
|
||||
membershipFee, err := s.web3Config.RLNContract.MEMBERSHIPDEPOSIT(&bind.CallOpts{Context: context.TODO()})
|
||||
s.Require().NoError(err)
|
||||
|
||||
auth, err := bind.NewKeyedTransactorWithChainID(privKey, s.chainID)
|
||||
auth, err := bind.NewKeyedTransactorWithChainID(privKey, s.web3Config.ChainID)
|
||||
s.Require().NoError(err)
|
||||
|
||||
auth.Value = membershipFee
|
||||
auth.Context = context.TODO()
|
||||
|
||||
tx, err := s.rlnContract.Register(auth, rln.Bytes32ToBigInt(identityCredential.IDCommitment))
|
||||
s.Require().NoError(err)
|
||||
txReceipt, err := bind.WaitMined(context.TODO(), s.backend, tx)
|
||||
tx, err := s.web3Config.RegistryContract.Register(auth, s.web3Config.RLNContract.StorageIndex, rln.Bytes32ToBigInt(identityCredential.IDCommitment))
|
||||
s.Require().NoError(err)
|
||||
|
||||
txReceipt, err := bind.WaitMined(context.TODO(), s.web3Config.ETHClient, tx)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(txReceipt.Status, types.ReceiptStatusSuccessful)
|
||||
|
||||
evt, err := s.rlnContract.ParseMemberRegistered(*txReceipt.Logs[0])
|
||||
evt, err := s.web3Config.RLNContract.ParseMemberRegistered(*txReceipt.Logs[0])
|
||||
s.Require().NoError(err)
|
||||
|
||||
membershipIndex := rln.MembershipIndex(uint(evt.Index.Int64()))
|
||||
|
@ -125,7 +126,7 @@ func (s *WakuRLNRelayDynamicSuite) register(appKeystore *keystore.AppKeystore, i
|
|||
membershipCredential := keystore.MembershipCredentials{
|
||||
IdentityCredential: identityCredential,
|
||||
TreeIndex: membershipIndex,
|
||||
MembershipContractInfo: keystore.NewMembershipContractInfo(s.chainID, s.rlnAddr),
|
||||
MembershipContractInfo: keystore.NewMembershipContractInfo(s.web3Config.ChainID, s.web3Config.RegistryContract.Address),
|
||||
}
|
||||
|
||||
err = appKeystore.AddMembershipCredentials(membershipCredential, keystorePassword)
|
||||
|
@ -143,14 +144,12 @@ func (s *WakuRLNRelayDynamicSuite) TestDynamicGroupManagement() {
|
|||
s.Require().NoError(err)
|
||||
|
||||
u1Credentials := s.generateCredentials(rlnInstance)
|
||||
keystorePath1 := "./test_onchain.json"
|
||||
appKeystore, err := keystore.New(keystorePath1, dynamic.RLNAppInfo, utils.Logger())
|
||||
appKeystore, err := keystore.New(s.tmpKeystorePath(), dynamic.RLNAppInfo, utils.Logger())
|
||||
s.Require().NoError(err)
|
||||
|
||||
membershipIndex := s.register(appKeystore, u1Credentials, s.u1PrivKey)
|
||||
defer s.removeCredentials(keystorePath1)
|
||||
|
||||
gm, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.rlnAddr, membershipIndex, appKeystore, keystorePassword, prometheus.DefaultRegisterer, utils.Logger())
|
||||
gm, err := dynamic.NewDynamicGroupManager(s.web3Config.ETHClientAddress, s.web3Config.RegistryContract.Address, membershipIndex, appKeystore, keystorePassword, prometheus.DefaultRegisterer, utils.Logger())
|
||||
s.Require().NoError(err)
|
||||
|
||||
// initialize the WakuRLNRelay
|
||||
|
@ -166,12 +165,10 @@ func (s *WakuRLNRelayDynamicSuite) TestDynamicGroupManagement() {
|
|||
s.Require().NoError(err)
|
||||
|
||||
u2Credentials := s.generateCredentials(rlnInstance)
|
||||
keystorePath2 := "./test_onchain2.json"
|
||||
appKeystore2, err := keystore.New(keystorePath2, dynamic.RLNAppInfo, utils.Logger())
|
||||
appKeystore2, err := keystore.New(s.tmpKeystorePath(), dynamic.RLNAppInfo, utils.Logger())
|
||||
s.Require().NoError(err)
|
||||
|
||||
membershipIndex = s.register(appKeystore2, u2Credentials, s.u2PrivKey)
|
||||
defer s.removeCredentials(keystorePath2)
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
|
@ -189,24 +186,25 @@ func (s *WakuRLNRelayDynamicSuite) TestInsertKeyMembershipContract() {
|
|||
credentials2 := s.generateCredentials(rlnInstance)
|
||||
credentials3 := s.generateCredentials(rlnInstance)
|
||||
|
||||
keystorePath1 := "./test_onchain.json"
|
||||
appKeystore, err := keystore.New(keystorePath1, dynamic.RLNAppInfo, utils.Logger())
|
||||
appKeystore, err := keystore.New(s.tmpKeystorePath(), dynamic.RLNAppInfo, utils.Logger())
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.register(appKeystore, credentials1, s.u1PrivKey)
|
||||
defer s.removeCredentials(keystorePath1)
|
||||
|
||||
// Batch Register
|
||||
auth, err := bind.NewKeyedTransactorWithChainID(s.u2PrivKey, s.chainID)
|
||||
auth, err := bind.NewKeyedTransactorWithChainID(s.u2PrivKey, s.web3Config.ChainID)
|
||||
s.Require().NoError(err)
|
||||
|
||||
membershipFee, err := s.web3Config.RLNContract.MEMBERSHIPDEPOSIT(&bind.CallOpts{Context: context.TODO()})
|
||||
s.Require().NoError(err)
|
||||
|
||||
auth.Value = membershipFee.Mul(big.NewInt(2), membershipFee)
|
||||
auth.Context = context.TODO()
|
||||
|
||||
tx, err := s.rlnContract.RegisterBatch(auth, []*big.Int{rln.Bytes32ToBigInt(credentials2.IDCommitment), rln.Bytes32ToBigInt(credentials3.IDCommitment)})
|
||||
tx, err := s.web3Config.RegistryContract.Register1(auth, s.web3Config.RLNContract.StorageIndex, []*big.Int{rln.Bytes32ToBigInt(credentials2.IDCommitment), rln.Bytes32ToBigInt(credentials3.IDCommitment)})
|
||||
s.Require().NoError(err)
|
||||
|
||||
txReceipt, err := bind.WaitMined(context.TODO(), s.backend, tx)
|
||||
txReceipt, err := bind.WaitMined(context.TODO(), s.web3Config.ETHClient, tx)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(txReceipt.Status, types.ReceiptStatusSuccessful)
|
||||
}
|
||||
|
@ -219,10 +217,7 @@ func (s *WakuRLNRelayDynamicSuite) TestMerkleTreeConstruction() {
|
|||
credentials1 := s.generateCredentials(rlnInstance)
|
||||
credentials2 := s.generateCredentials(rlnInstance)
|
||||
|
||||
err = rlnInstance.InsertMember(credentials1.IDCommitment)
|
||||
s.Require().NoError(err)
|
||||
|
||||
err = rlnInstance.InsertMember(credentials2.IDCommitment)
|
||||
err = rlnInstance.InsertMembers(1, []rln.IDCommitment{credentials1.IDCommitment, credentials2.IDCommitment})
|
||||
s.Require().NoError(err)
|
||||
|
||||
// get the Merkle root
|
||||
|
@ -230,21 +225,17 @@ func (s *WakuRLNRelayDynamicSuite) TestMerkleTreeConstruction() {
|
|||
s.Require().NoError(err)
|
||||
|
||||
// register the members to the contract
|
||||
keystorePath1 := "./test_onchain.json"
|
||||
appKeystore, err := keystore.New(keystorePath1, dynamic.RLNAppInfo, utils.Logger())
|
||||
appKeystore, err := keystore.New(s.tmpKeystorePath(), 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
|
||||
gm, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.rlnAddr, membershipIndex, appKeystore, keystorePassword, prometheus.DefaultRegisterer, utils.Logger())
|
||||
|
||||
gm, err := dynamic.NewDynamicGroupManager(s.web3Config.ETHClientAddress, s.web3Config.RegistryContract.Address, membershipIndex, appKeystore, keystorePassword, prometheus.DefaultRegisterer, utils.Logger())
|
||||
s.Require().NoError(err)
|
||||
|
||||
rlnRelay, err := New(gm, "test-merkle-tree.db", timesource.NewDefaultClock(), prometheus.DefaultRegisterer, utils.Logger())
|
||||
rlnRelay, err := New(gm, s.tmpRLNDBPath(), timesource.NewDefaultClock(), prometheus.DefaultRegisterer, utils.Logger())
|
||||
s.Require().NoError(err)
|
||||
|
||||
err = rlnRelay.Start(context.TODO())
|
||||
|
@ -257,7 +248,6 @@ func (s *WakuRLNRelayDynamicSuite) TestMerkleTreeConstruction() {
|
|||
// is expected to be the same as the calculatedRoot i.e., the one calculated outside of the mountRlnRelayDynamic proc
|
||||
calculatedRoot, err := rlnRelay.RLN.GetMerkleRoot()
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.Require().Equal(expectedRoot, calculatedRoot)
|
||||
}
|
||||
|
||||
|
@ -270,17 +260,15 @@ func (s *WakuRLNRelayDynamicSuite) TestCorrectRegistrationOfPeers() {
|
|||
|
||||
// Register credentials1 in contract and keystore1
|
||||
credentials1 := s.generateCredentials(rlnInstance)
|
||||
keystorePath1 := "./test_onchain.json"
|
||||
appKeystore, err := keystore.New(keystorePath1, dynamic.RLNAppInfo, utils.Logger())
|
||||
appKeystore, err := keystore.New(s.tmpKeystorePath(), dynamic.RLNAppInfo, utils.Logger())
|
||||
s.Require().NoError(err)
|
||||
membershipGroupIndex := s.register(appKeystore, credentials1, s.u1PrivKey)
|
||||
defer s.removeCredentials(keystorePath1)
|
||||
|
||||
// mount the rln relay protocol in the on-chain/dynamic mode
|
||||
gm1, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.rlnAddr, membershipGroupIndex, appKeystore, keystorePassword, prometheus.DefaultRegisterer, utils.Logger())
|
||||
gm1, err := dynamic.NewDynamicGroupManager(s.web3Config.ETHClientAddress, s.web3Config.RegistryContract.Address, membershipGroupIndex, appKeystore, keystorePassword, prometheus.DefaultRegisterer, utils.Logger())
|
||||
s.Require().NoError(err)
|
||||
|
||||
rlnRelay1, err := New(gm1, "test-correct-registration-1.db", timesource.NewDefaultClock(), prometheus.DefaultRegisterer, utils.Logger())
|
||||
rlnRelay1, err := New(gm1, s.tmpRLNDBPath(), timesource.NewDefaultClock(), prometheus.DefaultRegisterer, utils.Logger())
|
||||
s.Require().NoError(err)
|
||||
err = rlnRelay1.Start(context.TODO())
|
||||
s.Require().NoError(err)
|
||||
|
@ -289,17 +277,16 @@ func (s *WakuRLNRelayDynamicSuite) TestCorrectRegistrationOfPeers() {
|
|||
|
||||
// Register credentials2 in contract and keystore2
|
||||
credentials2 := s.generateCredentials(rlnInstance)
|
||||
keystorePath2 := "./test_onchain2.json"
|
||||
appKeystore2, err := keystore.New(keystorePath2, dynamic.RLNAppInfo, utils.Logger())
|
||||
appKeystore2, err := keystore.New(s.tmpKeystorePath(), dynamic.RLNAppInfo, utils.Logger())
|
||||
s.Require().NoError(err)
|
||||
|
||||
membershipGroupIndex = s.register(appKeystore2, credentials2, s.u2PrivKey)
|
||||
defer s.removeCredentials(keystorePath2)
|
||||
|
||||
// mount the rln relay protocol in the on-chain/dynamic mode
|
||||
gm2, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.rlnAddr, membershipGroupIndex, appKeystore2, keystorePassword, prometheus.DefaultRegisterer, utils.Logger())
|
||||
gm2, err := dynamic.NewDynamicGroupManager(s.web3Config.ETHClientAddress, s.web3Config.RegistryContract.Address, membershipGroupIndex, appKeystore2, keystorePassword, prometheus.DefaultRegisterer, utils.Logger())
|
||||
s.Require().NoError(err)
|
||||
|
||||
rlnRelay2, err := New(gm2, "test-correct-registration-2.db", timesource.NewDefaultClock(), prometheus.DefaultRegisterer, utils.Logger())
|
||||
rlnRelay2, err := New(gm2, s.tmpRLNDBPath(), timesource.NewDefaultClock(), prometheus.DefaultRegisterer, utils.Logger())
|
||||
s.Require().NoError(err)
|
||||
err = rlnRelay2.Start(context.TODO())
|
||||
s.Require().NoError(err)
|
||||
|
@ -311,7 +298,18 @@ func (s *WakuRLNRelayDynamicSuite) TestCorrectRegistrationOfPeers() {
|
|||
idx1 := rlnRelay1.groupManager.MembershipIndex()
|
||||
idx2 := rlnRelay2.groupManager.MembershipIndex()
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.Require().Equal(rln.MembershipIndex(0), idx1)
|
||||
s.Require().Equal(rln.MembershipIndex(1), idx2)
|
||||
s.Require().Equal(rln.MembershipIndex(1), idx1)
|
||||
s.Require().Equal(rln.MembershipIndex(2), idx2)
|
||||
}
|
||||
|
||||
func (s *WakuRLNRelayDynamicSuite) tmpKeystorePath() string {
|
||||
keystoreDir, err := os.MkdirTemp("", "keystore_dir")
|
||||
s.Require().NoError(err)
|
||||
return filepath.Join(keystoreDir, "keystore.json")
|
||||
}
|
||||
|
||||
func (s *WakuRLNRelayDynamicSuite) tmpRLNDBPath() string {
|
||||
dbPath, err := os.MkdirTemp("", "rln_db")
|
||||
s.Require().NoError(err)
|
||||
return dbPath
|
||||
}
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
package web3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol/rln/contracts"
|
||||
)
|
||||
|
||||
// RegistryContract contains an instance of the RLN Registry contract and its address
|
||||
type RegistryContract struct {
|
||||
*contracts.RLNRegistry
|
||||
Address common.Address
|
||||
}
|
||||
|
||||
// RLNContract contains an instance of the RLN contract, its address and the storage index within the registry
|
||||
// that represents this contract
|
||||
type RLNContract struct {
|
||||
*contracts.RLN
|
||||
Address common.Address
|
||||
StorageIndex uint16
|
||||
}
|
||||
|
||||
// Config is a helper struct that contains attributes for interaction with RLN smart contracts
|
||||
type Config struct {
|
||||
configured bool
|
||||
|
||||
ETHClientAddress string
|
||||
ETHClient *ethclient.Client
|
||||
ChainID *big.Int
|
||||
RegistryContract RegistryContract
|
||||
RLNContract RLNContract
|
||||
}
|
||||
|
||||
// NewConfig creates an instance of web3 Config
|
||||
func NewConfig(ethClientAddress string, registryAddress common.Address) *Config {
|
||||
return &Config{
|
||||
ETHClientAddress: ethClientAddress,
|
||||
RegistryContract: RegistryContract{
|
||||
Address: registryAddress,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// BuildConfig returns an instance of Web3Config with all the required elements for interaction with the RLN smart contracts
|
||||
func BuildConfig(ctx context.Context, ethClientAddress string, registryAddress common.Address) (*Config, error) {
|
||||
ethClient, err := ethclient.Dial(ethClientAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chainID, err := ethClient.ChainID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rlnRegistry, err := contracts.NewRLNRegistry(registryAddress, ethClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
storageIndex, err := rlnRegistry.UsingStorageIndex(&bind.CallOpts{Context: ctx})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rlnContractAddress, err := rlnRegistry.Storages(&bind.CallOpts{Context: ctx}, storageIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rlnContract, err := contracts.NewRLN(rlnContractAddress, ethClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Config{
|
||||
configured: true,
|
||||
ETHClientAddress: ethClientAddress,
|
||||
ETHClient: ethClient,
|
||||
ChainID: chainID,
|
||||
RegistryContract: RegistryContract{
|
||||
RLNRegistry: rlnRegistry,
|
||||
Address: registryAddress,
|
||||
},
|
||||
RLNContract: RLNContract{
|
||||
RLN: rlnContract,
|
||||
Address: rlnContractAddress,
|
||||
StorageIndex: storageIndex,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Build sets up the Config object by instantiating the eth client and contracts
|
||||
func (w *Config) Build(ctx context.Context) error {
|
||||
if w.configured {
|
||||
return errors.New("already configured")
|
||||
}
|
||||
|
||||
if w.ETHClientAddress == "" {
|
||||
return errors.New("no eth client address")
|
||||
}
|
||||
|
||||
var zeroAddr common.Address
|
||||
if w.RegistryContract.Address == zeroAddr {
|
||||
return errors.New("no registry contract address")
|
||||
}
|
||||
|
||||
newW, err := BuildConfig(ctx, w.ETHClientAddress, w.RegistryContract.Address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*w = *newW
|
||||
w.configured = true
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue