2022-08-10 17:10:23 +00:00
//go:build include_onchain_tests
// +build include_onchain_tests
2022-08-10 13:03:25 +00:00
package rln
import (
"context"
"crypto/ecdsa"
2023-08-18 21:38:30 +00:00
"fmt"
2022-08-10 13:03:25 +00:00
"math/big"
2023-04-26 16:13:13 +00:00
"os"
2022-08-10 13:03:25 +00:00
"testing"
"time"
2023-08-22 19:30:04 +00:00
"github.com/prometheus/client_golang/prometheus"
2023-04-26 15:55:03 +00:00
"github.com/waku-org/go-zerokit-rln/rln"
2023-08-18 21:38:30 +00:00
"go.uber.org/zap"
2023-04-26 15:55:03 +00:00
2022-08-10 13:03:25 +00:00
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
2023-08-18 21:38:30 +00:00
"github.com/ethereum/go-ethereum/core/types"
2022-08-10 13:03:25 +00:00
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/stretchr/testify/suite"
2022-11-09 19:53:01 +00:00
"github.com/waku-org/go-waku/waku/v2/protocol/rln/contracts"
2023-04-26 15:55:03 +00:00
"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"
2023-08-18 21:38:30 +00:00
"github.com/waku-org/go-waku/waku/v2/protocol/rln/keystore"
2023-01-06 22:37:57 +00:00
"github.com/waku-org/go-waku/waku/v2/timesource"
2022-11-09 19:53:01 +00:00
"github.com/waku-org/go-waku/waku/v2/utils"
2022-08-10 13:03:25 +00:00
)
2023-08-18 21:38:30 +00:00
var membershipFee = big . NewInt ( 1000000000000000 ) // wei - 0.001 eth
const keystorePassword = "test"
2023-04-26 15:55:03 +00:00
2022-08-10 13:03:25 +00:00
func TestWakuRLNRelayDynamicSuite ( t * testing . T ) {
suite . Run ( t , new ( WakuRLNRelayDynamicSuite ) )
}
type WakuRLNRelayDynamicSuite struct {
suite . Suite
2023-04-26 16:13:13 +00:00
clientAddr string
2022-08-10 13:03:25 +00:00
backend * ethclient . Client
chainID * big . Int
rlnAddr common . Address
rlnContract * contracts . RLN
u1PrivKey * ecdsa . PrivateKey
u2PrivKey * ecdsa . PrivateKey
}
2023-08-18 21:38:30 +00:00
// TODO: on teardown, remove credentials
2022-08-10 13:03:25 +00:00
func ( s * WakuRLNRelayDynamicSuite ) SetupTest ( ) {
2023-04-26 16:13:13 +00:00
s . clientAddr = os . Getenv ( "GANACHE_NETWORK_RPC_URL" )
if s . clientAddr == "" {
s . clientAddr = "ws://localhost:8545"
}
backend , err := ethclient . Dial ( s . clientAddr )
2022-08-10 13:03:25 +00:00
s . Require ( ) . NoError ( err )
chainID , err := backend . ChainID ( context . TODO ( ) )
s . Require ( ) . NoError ( err )
// TODO: obtain account list from ganache mnemonic or from eth_accounts
s . u1PrivKey , err = crypto . ToECDSA ( common . FromHex ( "0x156ec84a451d8a2d0062993242b6c4e863647f5544ff8030f23578d4142f43f8" ) )
s . Require ( ) . NoError ( err )
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 )
poseidonHasherAddr , _ , _ , err := contracts . DeployPoseidonHasher ( auth , backend )
s . Require ( ) . NoError ( err )
2023-08-18 21:38:30 +00:00
rlnAddr , _ , rlnContract , err := contracts . DeployRLN ( auth , backend , membershipFee , big . NewInt ( 20 ) , poseidonHasherAddr )
2022-08-10 13:03:25 +00:00
s . Require ( ) . NoError ( err )
s . rlnAddr = rlnAddr
s . rlnContract = rlnContract
}
2023-08-18 21:38:30 +00:00
func ( s * WakuRLNRelayDynamicSuite ) removeCredentials ( path string ) {
err := os . Remove ( path )
if err != nil {
utils . Logger ( ) . Warn ( "could not remove credentials" , zap . String ( "path" , path ) )
}
}
func ( s * WakuRLNRelayDynamicSuite ) generateCredentials ( rlnInstance * rln . RLN ) * rln . IdentityCredential {
identityCredential , err := rlnInstance . MembershipKeyGen ( )
s . Require ( ) . NoError ( err )
return identityCredential
}
func ( s * WakuRLNRelayDynamicSuite ) register ( identityCredential * rln . IdentityCredential , privKey * ecdsa . PrivateKey , keystorePath string ) ( rln . MembershipIndex , uint ) {
2022-08-10 13:03:25 +00:00
auth , err := bind . NewKeyedTransactorWithChainID ( privKey , s . chainID )
s . Require ( ) . NoError ( err )
2023-08-18 21:38:30 +00:00
auth . Value = membershipFee
2022-08-10 13:03:25 +00:00
auth . Context = context . TODO ( )
2023-08-18 21:38:30 +00:00
tx , err := s . rlnContract . Register ( auth , rln . Bytes32ToBigInt ( identityCredential . IDCommitment ) )
2022-08-10 13:03:25 +00:00
s . Require ( ) . NoError ( err )
2023-08-18 21:38:30 +00:00
txReceipt , err := bind . WaitMined ( context . TODO ( ) , s . backend , tx )
2023-04-26 15:55:03 +00:00
s . Require ( ) . NoError ( err )
2023-08-18 21:38:30 +00:00
s . Require ( ) . Equal ( txReceipt . Status , types . ReceiptStatusSuccessful )
evt , err := s . rlnContract . ParseMemberRegistered ( * txReceipt . Logs [ 0 ] )
2022-08-10 13:03:25 +00:00
s . Require ( ) . NoError ( err )
2023-04-26 15:55:03 +00:00
2023-08-18 21:38:30 +00:00
membershipIndex := rln . MembershipIndex ( uint ( evt . Index . Int64 ( ) ) )
membershipGroup := keystore . MembershipGroup {
TreeIndex : membershipIndex ,
MembershipContract : keystore . MembershipContract {
ChainId : fmt . Sprintf ( "0x%X" , s . chainID . Int64 ( ) ) ,
Address : s . rlnAddr . String ( ) ,
} ,
2023-04-26 15:55:03 +00:00
}
2023-08-18 21:38:30 +00:00
membershipGroupIndex , err := keystore . AddMembershipCredentials ( keystorePath , identityCredential , membershipGroup , keystorePassword , dynamic . RLNAppInfo , keystore . DefaultSeparator )
s . Require ( ) . NoError ( err )
return membershipIndex , membershipGroupIndex
2022-08-10 13:03:25 +00:00
}
func ( s * WakuRLNRelayDynamicSuite ) TestDynamicGroupManagement ( ) {
// Create a RLN instance
2023-08-18 13:59:37 +00:00
rlnInstance , err := rln . NewRLN ( )
2022-08-10 13:03:25 +00:00
s . Require ( ) . NoError ( err )
2023-04-26 15:55:03 +00:00
rt , err := group_manager . NewMerkleRootTracker ( 5 , rlnInstance )
s . Require ( ) . NoError ( err )
2023-08-18 21:38:30 +00:00
u1Credentials := s . generateCredentials ( rlnInstance )
keystorePath1 := "./test_onchain.json"
_ , membershipGroupIndex := s . register ( u1Credentials , s . u1PrivKey , keystorePath1 )
defer s . removeCredentials ( keystorePath1 )
2023-08-22 19:30:04 +00:00
gm , err := dynamic . NewDynamicGroupManager ( s . clientAddr , s . rlnAddr , membershipGroupIndex , keystorePath1 , keystorePassword , 0 , false , prometheus . DefaultRegisterer , utils . Logger ( ) )
2022-08-10 13:03:25 +00:00
s . Require ( ) . NoError ( err )
// initialize the WakuRLNRelay
2023-04-26 15:55:03 +00:00
rlnRelay := & WakuRLNRelay {
rootTracker : rt ,
groupManager : gm ,
RLN : rlnInstance ,
log : utils . Logger ( ) ,
2023-08-18 13:59:37 +00:00
nullifierLog : make ( map [ rln . MerkleNode ] [ ] rln . ProofMetadata ) ,
2022-08-10 13:03:25 +00:00
}
2023-08-18 21:38:30 +00:00
err = rlnRelay . Start ( context . TODO ( ) )
2023-04-26 15:55:03 +00:00
s . Require ( ) . NoError ( err )
2023-08-18 21:38:30 +00:00
u2Credentials := s . generateCredentials ( rlnInstance )
keystorePath2 := "./test_onchain2.json"
membershipIndex , _ := s . register ( u2Credentials , s . u2PrivKey , keystorePath2 )
defer s . removeCredentials ( keystorePath2 )
2022-08-10 13:03:25 +00:00
2023-08-18 21:38:30 +00:00
time . Sleep ( 1 * time . Second )
2022-08-10 13:03:25 +00:00
2023-08-18 21:38:30 +00:00
treeCommitment , err := rlnInstance . GetLeaf ( membershipIndex )
s . Require ( ) . NoError ( err )
s . Require ( ) . Equal ( u2Credentials . IDCommitment , treeCommitment )
2022-08-10 13:03:25 +00:00
}
func ( s * WakuRLNRelayDynamicSuite ) TestInsertKeyMembershipContract ( ) {
2023-08-18 21:38:30 +00:00
// Create a RLN instance
rlnInstance , err := rln . NewRLN ( )
s . Require ( ) . NoError ( err )
2022-08-10 13:03:25 +00:00
2023-08-18 21:38:30 +00:00
credentials1 := s . generateCredentials ( rlnInstance )
credentials2 := s . generateCredentials ( rlnInstance )
credentials3 := s . generateCredentials ( rlnInstance )
keystorePath1 := "./test_onchain.json"
s . register ( credentials1 , s . u1PrivKey , keystorePath1 )
defer s . removeCredentials ( keystorePath1 )
2022-08-10 13:03:25 +00:00
// Batch Register
auth , err := bind . NewKeyedTransactorWithChainID ( s . u2PrivKey , s . chainID )
s . Require ( ) . NoError ( err )
2023-08-18 21:38:30 +00:00
auth . Value = membershipFee . Mul ( big . NewInt ( 2 ) , membershipFee )
2022-08-10 13:03:25 +00:00
auth . Context = context . TODO ( )
2023-08-18 21:38:30 +00:00
tx , err := s . rlnContract . RegisterBatch ( auth , [ ] * big . Int { rln . Bytes32ToBigInt ( credentials2 . IDCommitment ) , rln . Bytes32ToBigInt ( credentials3 . IDCommitment ) } )
2022-08-10 13:03:25 +00:00
s . Require ( ) . NoError ( err )
2023-08-18 21:38:30 +00:00
txReceipt , err := bind . WaitMined ( context . TODO ( ) , s . backend , tx )
2022-08-10 13:03:25 +00:00
s . Require ( ) . NoError ( err )
2023-08-18 21:38:30 +00:00
s . Require ( ) . Equal ( txReceipt . Status , types . ReceiptStatusSuccessful )
2022-08-10 13:03:25 +00:00
}
func ( s * WakuRLNRelayDynamicSuite ) TestMerkleTreeConstruction ( ) {
// Create a RLN instance
2023-08-18 13:59:37 +00:00
rlnInstance , err := rln . NewRLN ( )
2022-08-10 13:03:25 +00:00
s . Require ( ) . NoError ( err )
2023-08-18 21:38:30 +00:00
credentials1 := s . generateCredentials ( rlnInstance )
credentials2 := s . generateCredentials ( rlnInstance )
2022-08-10 13:03:25 +00:00
2023-08-18 21:38:30 +00:00
err = rlnInstance . InsertMember ( credentials1 . IDCommitment )
2022-08-10 13:03:25 +00:00
s . Require ( ) . NoError ( err )
2023-08-18 21:38:30 +00:00
err = rlnInstance . InsertMember ( credentials2 . IDCommitment )
2022-10-04 23:15:39 +00:00
s . Require ( ) . NoError ( err )
2022-08-10 13:03:25 +00:00
// get the Merkle root
expectedRoot , err := rlnInstance . GetMerkleRoot ( )
s . Require ( ) . NoError ( err )
// register the members to the contract
2023-08-18 21:38:30 +00:00
_ , membershipGroupIndex := s . register ( credentials1 , s . u1PrivKey , "./test_onchain.json" )
_ , membershipGroupIndex = s . register ( credentials2 , s . u1PrivKey , "./test_onchain.json" )
2022-08-10 13:03:25 +00:00
// mount the rln relay protocol in the on-chain/dynamic mode
2023-08-18 21:38:30 +00:00
// TODO: This assumes the keystoreIndex is 0, but there are two possible credentials in this keystore due to using the same contract address
// 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 )
2023-08-22 19:30:04 +00:00
gm , err := dynamic . NewDynamicGroupManager ( s . clientAddr , s . rlnAddr , membershipGroupIndex , "./test_onchain.json" , keystorePassword , keystoreIndex , false , prometheus . DefaultRegisterer , utils . Logger ( ) )
2023-04-26 15:55:03 +00:00
s . Require ( ) . NoError ( err )
2023-08-22 19:30:04 +00:00
rlnRelay , err := New ( gm , "test-merkle-tree.db" , timesource . NewDefaultClock ( ) , prometheus . DefaultRegisterer , utils . Logger ( ) )
2023-04-26 15:55:03 +00:00
s . Require ( ) . NoError ( err )
err = rlnRelay . Start ( context . TODO ( ) )
2022-08-10 13:03:25 +00:00
s . Require ( ) . NoError ( err )
// wait for the event to reach the group handler
2023-01-06 22:37:57 +00:00
time . Sleep ( 2 * time . Second )
2022-08-10 13:03:25 +00:00
// rln pks are inserted into the rln peer's Merkle tree and the resulting root
// 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 )
}
func ( s * WakuRLNRelayDynamicSuite ) TestCorrectRegistrationOfPeers ( ) {
2023-08-18 21:38:30 +00:00
// Creating an RLN instance (just for generating membership keys)
rlnInstance , err := rln . NewRLN ( )
s . Require ( ) . NoError ( err )
2022-08-10 13:03:25 +00:00
// Node 1 ============================================================
2023-08-18 21:38:30 +00:00
// Register credentials1 in contract and keystore1
credentials1 := s . generateCredentials ( rlnInstance )
keystorePath1 := "./test_onchain.json"
_ , membershipGroupIndex := s . register ( credentials1 , s . u1PrivKey , keystorePath1 )
defer s . removeCredentials ( keystorePath1 )
2022-08-10 13:03:25 +00:00
// mount the rln relay protocol in the on-chain/dynamic mode
2023-08-22 19:30:04 +00:00
gm1 , err := dynamic . NewDynamicGroupManager ( s . clientAddr , s . rlnAddr , membershipGroupIndex , keystorePath1 , keystorePassword , 0 , false , prometheus . DefaultRegisterer , utils . Logger ( ) )
2023-04-26 15:55:03 +00:00
s . Require ( ) . NoError ( err )
2023-08-22 19:30:04 +00:00
rlnRelay1 , err := New ( gm1 , "test-correct-registration-1.db" , timesource . NewDefaultClock ( ) , prometheus . DefaultRegisterer , utils . Logger ( ) )
2023-04-26 15:55:03 +00:00
s . Require ( ) . NoError ( err )
err = rlnRelay1 . Start ( context . TODO ( ) )
2022-08-10 13:03:25 +00:00
s . Require ( ) . NoError ( err )
// Node 2 ============================================================
2023-08-18 21:38:30 +00:00
// Register credentials2 in contract and keystore2
credentials2 := s . generateCredentials ( rlnInstance )
keystorePath2 := "./test_onchain2.json"
_ , membershipGroupIndex = s . register ( credentials2 , s . u2PrivKey , keystorePath2 )
defer s . removeCredentials ( keystorePath2 )
2022-08-10 13:03:25 +00:00
// mount the rln relay protocol in the on-chain/dynamic mode
2023-08-22 19:30:04 +00:00
gm2 , err := dynamic . NewDynamicGroupManager ( s . clientAddr , s . rlnAddr , membershipGroupIndex , keystorePath2 , keystorePassword , 0 , false , prometheus . DefaultRegisterer , utils . Logger ( ) )
2023-04-26 15:55:03 +00:00
s . Require ( ) . NoError ( err )
2023-08-22 19:30:04 +00:00
rlnRelay2 , err := New ( gm2 , "test-correct-registration-2.db" , timesource . NewDefaultClock ( ) , prometheus . DefaultRegisterer , utils . Logger ( ) )
2023-04-26 15:55:03 +00:00
s . Require ( ) . NoError ( err )
err = rlnRelay2 . Start ( context . TODO ( ) )
2022-08-10 13:03:25 +00:00
s . Require ( ) . NoError ( err )
// ==================================
// the two nodes should be registered into the contract
// since nodes are spun up sequentially
// the first node has index 0 whereas the second node gets index 1
2023-04-26 15:55:03 +00:00
idx1 , err := rlnRelay1 . groupManager . MembershipIndex ( )
s . Require ( ) . NoError ( err )
idx2 , err := rlnRelay2 . groupManager . MembershipIndex ( )
s . Require ( ) . NoError ( err )
2023-08-18 13:59:37 +00:00
s . Require ( ) . Equal ( rln . MembershipIndex ( 0 ) , idx1 )
s . Require ( ) . Equal ( rln . MembershipIndex ( 1 ) , idx2 )
2022-08-10 13:03:25 +00:00
}