Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implemented RPC Manager for RPC calls #1260

Merged
merged 25 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
31a16c2
feature: introduced RPC manager module
Yashk767 Oct 25, 2024
47af47a
feat: Implemented RPCParameters for all contract calls
Yashk767 Nov 5, 2024
67b9aa9
refactor: moved RPCParameters struct to RPC module
Yashk767 Nov 5, 2024
ecc0987
fix: added assetId parameter to getActiveStatus retry call
Yashk767 Nov 5, 2024
798eb7e
refactor: passed rpcParameters to Batch call functions instead of client
Yashk767 Nov 5, 2024
add47de
fix: path to assets.json and client parameter index fixed
Yashk767 Nov 5, 2024
68113ae
refactor: tests/updated mocks
Yashk767 Nov 5, 2024
e1210b0
refactor: revert mainnet addresses change
Yashk767 Nov 5, 2024
5c800c5
fix: added ctx parameter in CheckTransactionReceipt
Yashk767 Nov 5, 2024
9af2fbf
fix: revert chain Id and contract addresses change
Yashk767 Nov 6, 2024
d8cd217
fix: refreshed RPC list after confirm state every epoch
Yashk767 Nov 6, 2024
df32b5e
fix: added disputes contract call to the blockManager struct
Yashk767 Nov 19, 2024
1ee3a25
refactor: fixed lint log error
Yashk767 Nov 19, 2024
e9e7fda
reafctor: fixed tests
Yashk767 Nov 19, 2024
88ebebb
fix: calculated dynamically the path to endpoints.json file
Yashk767 Nov 19, 2024
4e950f1
fix: endpoints.json file to be picked from .razor directory instaed o…
Yashk767 Nov 20, 2024
b657079
refactor: set up temp endpoints.json file for tests
Yashk767 Nov 20, 2024
2aa58b2
feat: added importEndpoints command
Yashk767 Nov 22, 2024
7fa4863
refactor: removed alternateProvider functions and flag as its not req…
Yashk767 Nov 25, 2024
0f23670
fix: switch to next client only if the connection is successful
Yashk767 Nov 26, 2024
7d55496
feat: added state block check by introducing blockMonitor (#1262)
Yashk767 Nov 27, 2024
faa6865
refactor: used BestRPCClient from BestEndpoint
Yashk767 Dec 3, 2024
5631ae4
refactor: renamed RPC module to rpc
Yashk767 Dec 3, 2024
ba30b03
refactor: removed unwanted logs
Yashk767 Dec 3, 2024
42e8cd0
refactor: corrected importEndpoints command info
Yashk767 Dec 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ $ ./razor setConfig --provider <rpc_provider> --gasmultiplier <multiplier_value>
docker

```
docker exec -it razor-go razor setConfig --provider <rpc_provider> --alternateProvider <alternate_rpc_provider> --gasmultiplier <multiplier_value> --buffer <buffer_percentage> --wait <wait_for_n_blocks> --gasprice <gas_price> --logLevel <debug_or_info> --gasLimit <gas_limit_multiplier> --rpcTimeout <rpc_timeout> --httpTimeout <http_timeout> --logFileMaxSize <file_max_size> --logFileMaxBackups <file_max_backups> --logFileMaxAge <file_max_age>
docker exec -it razor-go razor setConfig --provider <rpc_provider> --gasmultiplier <multiplier_value> --buffer <buffer_percentage> --wait <wait_for_n_blocks> --gasprice <gas_price> --logLevel <debug_or_info> --gasLimit <gas_limit_multiplier> --rpcTimeout <rpc_timeout> --httpTimeout <http_timeout> --logFileMaxSize <file_max_size> --logFileMaxBackups <file_max_backups> --logFileMaxAge <file_max_age>
```

Example:
Expand Down Expand Up @@ -190,6 +190,23 @@ Password:

_Before staking on Razor Network, please ensure your account has sFUEL and RAZOR. For testnet RAZOR, please contact us on Discord._

### Import Endpoints

You can import the endpoints to file `$HOME/.razor/endpoints.json` on your local by using the `importEndpoints` command.
This command imports multiple providers along with the user input provider, which are then sorted according to the best performance. The best provider is thus chosen by the RPC manager and will be used to make the RPC calls.

razor cli

```
$ ./razor importEndpoints
```

docker

```
docker exec -it razor-go razor importEndpoints
```

### Stake

If you have a minimum of 1000 razors in your account, you can stake those using the addStake command.
Expand Down
2 changes: 1 addition & 1 deletion accounts/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"strings"
)

var log = logger.NewLogger()
var log = logger.GetLogger()

//This function takes path and password as input and returns new account
func (am *AccountManager) CreateAccount(keystorePath string, password string) accounts.Account {
Expand Down
108 changes: 90 additions & 18 deletions block/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,112 @@ package block

import (
"context"
"razor/core"
"sync"
"time"

"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/sirupsen/logrus"
"razor/rpc"
)

var latestBlock *types.Header
var mu = sync.Mutex{}
// BlockMonitor monitors the latest block and handles stale blocks.
type BlockMonitor struct {
client *ethclient.Client
rpcManager *rpc.RPCManager
latestBlock *types.Header
mu sync.Mutex
checkInterval time.Duration
staleThreshold time.Duration
}

// NewBlockMonitor initializes a BlockMonitor with RPC integration.
func NewBlockMonitor(client *ethclient.Client, rpcManager *rpc.RPCManager, checkInterval, staleThreshold time.Duration) *BlockMonitor {
return &BlockMonitor{
client: client,
rpcManager: rpcManager,
checkInterval: time.Second * checkInterval,
staleThreshold: time.Second * staleThreshold,
}
}

func GetLatestBlock() *types.Header {
mu.Lock()
defer mu.Unlock()
return latestBlock
// Start begins the block monitoring process.
func (bm *BlockMonitor) Start() {
go func() {
for {
bm.updateLatestBlock()
bm.checkForStaleBlock()
time.Sleep(bm.checkInterval)
}
}()
}

func SetLatestBlock(block *types.Header) {
mu.Lock()
latestBlock = block
mu.Unlock()
// GetLatestBlock retrieves the most recent block header safely.
func (bm *BlockMonitor) GetLatestBlock() *types.Header {
bm.mu.Lock()
defer bm.mu.Unlock()
return bm.latestBlock
}

func CalculateLatestBlock(client *ethclient.Client) {
for {
if client != nil {
latestHeader, err := client.HeaderByNumber(context.Background(), nil)
// updateLatestBlock fetches the latest block and updates the state.
func (bm *BlockMonitor) updateLatestBlock() {
if bm.client == nil {
return
}

header, err := bm.client.HeaderByNumber(context.Background(), nil)
if err != nil {
logrus.Errorf("Error fetching latest block: %v", err)
return
}

bm.mu.Lock()
defer bm.mu.Unlock()

// Update the latest block only if it changes.
if bm.latestBlock == nil || header.Number.Uint64() != bm.latestBlock.Number.Uint64() {
bm.latestBlock = header
}
}

// checkForStaleBlock detects stale blocks and triggers appropriate actions.
func (bm *BlockMonitor) checkForStaleBlock() {
if bm.staleThreshold == 0 {
return
}

bm.mu.Lock()
defer bm.mu.Unlock()

if bm.latestBlock == nil || time.Since(time.Unix(int64(bm.latestBlock.Time), 0)) >= bm.staleThreshold {
logrus.Warnf("Stale block detected: Block %d is stale for %s", bm.latestBlock.Number.Uint64(), bm.staleThreshold)

// Switch to the next best RPC endpoint if stale block detected.
if bm.rpcManager != nil {
switched, err := bm.rpcManager.SwitchToNextBestRPCClient()
if err != nil {
logrus.Error("CalculateBlockNumber: Error in fetching block: ", err)
logrus.Errorf("Failed to switch RPC endpoint: %v", err)
} else if switched {
logrus.Info("Switched to the next best RPC endpoint.")
bm.updateClient()
} else {
SetLatestBlock(latestHeader)
logrus.Warn("Retaining the current best RPC endpoint as no valid alternate was found.")
}
}
time.Sleep(time.Second * time.Duration(core.BlockNumberInterval))
}
}

// updateClient updates the Ethereum client to use the new best RPC endpoint.
func (bm *BlockMonitor) updateClient() {
if bm.rpcManager == nil {
return
}

newClient, err := bm.rpcManager.GetBestRPCClient()
if err != nil {
return
}

bm.client = newClient
logrus.Info("Client in logger updated with the new best RPC endpoint.")
}
63 changes: 0 additions & 63 deletions client/alternateClient.go

This file was deleted.

65 changes: 23 additions & 42 deletions cmd/addStake.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@
package cmd

import (
"context"
"razor/accounts"
"razor/core"
"razor/core/types"
"razor/logger"
"razor/pkg/bindings"
"razor/rpc"
"razor/utils"

"github.com/spf13/pflag"
Expand All @@ -34,33 +32,11 @@ func initialiseStake(cmd *cobra.Command, args []string) {

//This function sets the flags appropriately and executes the StakeCoins function
func (*UtilsStruct) ExecuteStake(flagSet *pflag.FlagSet) {
config, err := cmdUtils.GetConfigData()
utils.CheckError("Error in getting config: ", err)
log.Debugf("ExecuteStake: config: %+v", config)
config, rpcParameters, account, err := InitializeCommandDependencies(flagSet)
utils.CheckError("Error in initialising command dependencies: ", err)

client := razorUtils.ConnectToClient(config.Provider)

address, err := flagSetUtils.GetStringAddress(flagSet)
utils.CheckError("Error in getting address: ", err)
log.Debug("ExecuteStake: Address: ", address)

logger.SetLoggerParameters(client, address)
log.Debug("Checking to assign log file...")
fileUtils.AssignLogFile(flagSet, config)

log.Debug("Getting password...")
password := razorUtils.AssignPassword(flagSet)

accountManager, err := razorUtils.AccountManagerForKeystore()
utils.CheckError("Error in getting accounts manager for keystore: ", err)

account := accounts.InitAccountStruct(address, password, accountManager)

err = razorUtils.CheckPassword(account)
utils.CheckError("Error in fetching private key from given password: ", err)

balance, err := razorUtils.FetchBalance(client, address)
utils.CheckError("Error in fetching razor balance for account: "+address, err)
balance, err := razorUtils.FetchBalance(rpcParameters, account.Address)
utils.CheckError("Error in fetching razor balance for account: "+account.Address, err)
log.Debug("Getting amount in wei...")
valueInWei, err := cmdUtils.AssignAmountInWei(flagSet)
utils.CheckError("Error in getting amount: ", err)
Expand All @@ -70,13 +46,13 @@ func (*UtilsStruct) ExecuteStake(flagSet *pflag.FlagSet) {
razorUtils.CheckAmountAndBalance(valueInWei, balance)

log.Debug("Checking whether sFUEL balance is not 0...")
razorUtils.CheckEthBalanceIsZero(context.Background(), client, address)
razorUtils.CheckEthBalanceIsZero(rpcParameters, account.Address)

minSafeRazor, err := razorUtils.GetMinSafeRazor(context.Background(), client)
minSafeRazor, err := razorUtils.GetMinSafeRazor(rpcParameters)
utils.CheckError("Error in getting minimum safe razor amount: ", err)
log.Debug("ExecuteStake: Minimum razor that you can stake for first time: ", minSafeRazor)

stakerId, err := razorUtils.GetStakerId(context.Background(), client, address)
stakerId, err := razorUtils.GetStakerId(rpcParameters, account.Address)
utils.CheckError("Error in getting stakerId: ", err)
log.Debug("ExecuteStake: Staker Id: ", stakerId)

Expand All @@ -85,7 +61,7 @@ func (*UtilsStruct) ExecuteStake(flagSet *pflag.FlagSet) {
}

if stakerId != 0 {
staker, err := razorUtils.GetStaker(context.Background(), client, stakerId)
staker, err := razorUtils.GetStaker(rpcParameters, stakerId)
utils.CheckError("Error in getting staker: ", err)

if staker.IsSlashed {
Expand All @@ -94,33 +70,32 @@ func (*UtilsStruct) ExecuteStake(flagSet *pflag.FlagSet) {
}

txnArgs := types.TransactionOptions{
Client: client,
Amount: valueInWei,
ChainId: core.ChainId,
Config: config,
Account: account,
}

log.Debug("ExecuteStake: Calling Approve() for amount: ", txnArgs.Amount)
approveTxnHash, err := cmdUtils.Approve(txnArgs)
approveTxnHash, err := cmdUtils.Approve(rpcParameters, txnArgs)
utils.CheckError("Approve error: ", err)

if approveTxnHash != core.NilHash {
err = razorUtils.WaitForBlockCompletion(txnArgs.Client, approveTxnHash.Hex())
err = razorUtils.WaitForBlockCompletion(rpcParameters, approveTxnHash.Hex())
utils.CheckError("Error in WaitForBlockCompletion for approve: ", err)
}

log.Debug("ExecuteStake: Calling StakeCoins() for amount: ", txnArgs.Amount)
stakeTxnHash, err := cmdUtils.StakeCoins(txnArgs)
stakeTxnHash, err := cmdUtils.StakeCoins(rpcParameters, txnArgs)
utils.CheckError("Stake error: ", err)

err = razorUtils.WaitForBlockCompletion(txnArgs.Client, stakeTxnHash.Hex())
err = razorUtils.WaitForBlockCompletion(rpcParameters, stakeTxnHash.Hex())
utils.CheckError("Error in WaitForBlockCompletion for stake: ", err)
}

//This function allows the user to stake razors in the razor network and returns the hash
func (*UtilsStruct) StakeCoins(txnArgs types.TransactionOptions) (common.Hash, error) {
epoch, err := razorUtils.GetEpoch(context.Background(), txnArgs.Client)
func (*UtilsStruct) StakeCoins(rpcParameters rpc.RPCParameters, txnArgs types.TransactionOptions) (common.Hash, error) {
epoch, err := razorUtils.GetEpoch(rpcParameters)
if err != nil {
return core.NilHash, err
}
Expand All @@ -130,9 +105,15 @@ func (*UtilsStruct) StakeCoins(txnArgs types.TransactionOptions) (common.Hash, e
txnArgs.MethodName = "stake"
txnArgs.Parameters = []interface{}{epoch, txnArgs.Amount}
txnArgs.ABI = bindings.StakeManagerMetaData.ABI
txnOpts := razorUtils.GetTxnOpts(context.Background(), txnArgs)
txnOpts := razorUtils.GetTxnOpts(rpcParameters, txnArgs)

client, err := rpcParameters.RPCManager.GetBestRPCClient()
if err != nil {
return core.NilHash, err
}

log.Debugf("Executing Stake transaction with epoch = %d, amount = %d", epoch, txnArgs.Amount)
txn, err := stakeManagerUtils.Stake(txnArgs.Client, txnOpts, epoch, txnArgs.Amount)
txn, err := stakeManagerUtils.Stake(client, txnOpts, epoch, txnArgs.Amount)
if err != nil {
return core.NilHash, err
}
Expand Down
Loading
Loading