harsh jain 08cabab41f
fix: and optimising fetching membership events (#706)
* fix: and optimising fetching membership events

* fix: start from lastProcessedBlock+1

* test: fetching membership logic

* refactor: usage of rlnInstance,rootTracker,groupManager

rlnInstance, rootTrack were previously created while creating rlnRelay
but were assigned to groupManager on Start of rlnRelay. This created
unncessary dependency of passing them to static and dynamic group
manager.
Web3Config uses interface EthClientI for client, so that we can pass
mock client for testing MembershipFetcher.

* fix: failing test

* fix: lint error

* fix: account for PR suggestions

* fix: failing race test

* fix: dont' increase fromBlock on error

* nit: fix naming and add comments
2023-09-07 23:23:48 +07:00

141 lines
3.7 KiB
Go

package web3
import (
"context"
"errors"
"math/big"
"github.com/ethereum/go-ethereum"
"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/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
DeployedBlockNumber uint64
}
// EthClient is an interface for the ethclient.Client, so that we can pass mock client for testing
type EthClient interface {
bind.ContractBackend
TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error)
SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (ethereum.Subscription, error)
Close()
}
// Config is a helper struct that contains attributes for interaction with RLN smart contracts
type Config struct {
configured bool
ETHClientAddress string
ETHClient EthClient
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.DialContext(ctx, 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
}
deploymentBlockNumber, err := rlnContract.DeployedBlockNumber(&bind.CallOpts{Context: ctx})
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,
DeployedBlockNumber: uint64(deploymentBlockNumber),
},
}, 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
}