From c12a45a03aad427aa10a1688a3204d5089ec3963 Mon Sep 17 00:00:00 2001 From: Yashk767 <76935991+Yashk767@users.noreply.github.com> Date: Thu, 20 Feb 2025 15:50:54 +0530 Subject: [PATCH 1/9] fix: removed cancel context being called immediately after creation (#1265) --- rpc/rpc.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/rpc/rpc.go b/rpc/rpc.go index 98d73cb9..f187a4d3 100644 --- a/rpc/rpc.go +++ b/rpc/rpc.go @@ -201,10 +201,10 @@ func (m *RPCManager) SwitchToNextBestRPCClient() (bool, error) { // Check if we can connect to the next endpoint ctx, cancel := context.WithTimeout(context.Background(), core.EndpointsContextTimeout*time.Second) - cancel() client, err := ethclient.DialContext(ctx, nextEndpoint.URL) if err != nil { + cancel() logrus.Errorf("Failed to connect to RPC endpoint %s: %v", nextEndpoint.URL, err) continue } @@ -212,12 +212,17 @@ func (m *RPCManager) SwitchToNextBestRPCClient() (bool, error) { // Try fetching block number to validate the endpoint _, err = m.fetchBlockNumberWithTimeout(ctx, client) if err != nil { + cancel() logrus.Errorf("Failed to fetch block number for endpoint %s: %v", nextEndpoint.URL, err) continue } + // Cancel the context after the operations complete. + cancel() + // Successfully connected and validated, update the best client and endpoint - m.BestEndpoint.Client = client + // (Make sure that the client is correctly associated with the endpoint.) + nextEndpoint.Client = client m.BestEndpoint = nextEndpoint logrus.Infof("Switched to the next best RPC endpoint: %s (BlockNumber: %d, Latency: %.2f)", From 0243b54c29121979ba169c80cd954a4cea8ec76d Mon Sep 17 00:00:00 2001 From: Yashk767 <76935991+Yashk767@users.noreply.github.com> Date: Wed, 26 Feb 2025 18:00:00 +0530 Subject: [PATCH 2/9] refactor: added tests for rpc module (#1266) * refactor: added tests for RPC module * Revert "refactor: added tests for RPC module" This reverts commit bac5b3b0e5c6eb7aced15ccd1694bd7c262c26f7. * reafctor: added tests for rpc module using httpstest servers * ci: updated artifact version for binary downloads and uploads * ci: fixed ci by updateing action versions * reafctor: replaced ts.cancel() with t.Cleanup(func() { ts1.Close() }) --- .github/workflows/ci.yml | 18 +- .github/workflows/develop.yml | 4 +- .github/workflows/release.yml | 4 +- rpc/rpc_test.go | 320 ++++++++++++++++++++++++++++++++++ 4 files changed, 333 insertions(+), 13 deletions(-) create mode 100644 rpc/rpc_test.go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bf585be5..b03d6cf9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "20" - name: Setup Go @@ -62,7 +62,7 @@ jobs: env: COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: goveralls -coverprofile=coverage.txt -service=github - - uses: bissolli/gh-action-persist-workspace@v1 + - uses: bissolli/gh-action-persist-workspace@v2 with: action: persist @@ -75,7 +75,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "20" @@ -105,7 +105,7 @@ jobs: mv razor_go.linux-amd64.tar.gz ../../ - name: Upload AMD Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: razor_go.linux-amd64.tar.gz path: razor_go.linux-amd64.tar.gz @@ -117,7 +117,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "20" @@ -147,7 +147,7 @@ jobs: mv razor_go.linux-arm64.tar.gz ../../ - name: Upload ARM Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: razor_go.linux-arm64.tar.gz path: razor_go.linux-arm64.tar.gz @@ -166,17 +166,17 @@ jobs: fetch-depth: 0 - name: Setup Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "20" - name: Download Artifacts AMD - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: razor_go.linux-amd64.tar.gz - name: Download Artifacts ARM - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: razor_go.linux-arm64.tar.gz diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index ec4fbf21..4ab39ca6 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -16,7 +16,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "20" - name: Setup Go @@ -68,7 +68,7 @@ jobs: env: COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: goveralls -coverprofile=coverage.txt -service=github - - uses: bissolli/gh-action-persist-workspace@v1 + - uses: bissolli/gh-action-persist-workspace@v2 with: action: persist diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f9f83d03..7736dece 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "20" - name: Setup Go @@ -65,7 +65,7 @@ jobs: env: COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: goveralls -coverprofile=coverage.txt -service=github - - uses: bissolli/gh-action-persist-workspace@v1 + - uses: bissolli/gh-action-persist-workspace@v2 with: action: persist diff --git a/rpc/rpc_test.go b/rpc/rpc_test.go new file mode 100644 index 00000000..f6187822 --- /dev/null +++ b/rpc/rpc_test.go @@ -0,0 +1,320 @@ +package rpc + +import ( + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "strconv" + "testing" + "time" +) + +// decodeRPCRequest decodes the JSON–RPC request body into a map. +func decodeRPCRequest(r *http.Request) (map[string]interface{}, error) { + var req map[string]interface{} + err := json.NewDecoder(r.Body).Decode(&req) + return req, err +} + +// writeRPCResponse writes the provided response as JSON with the appropriate header. +func writeRPCResponse(w http.ResponseWriter, response map[string]interface{}) { + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(response) +} + +// jsonRPCHandler simulates an Ethereum JSON–RPC endpoint that returns block number 100. +func jsonRPCHandler(w http.ResponseWriter, r *http.Request) { + req, err := decodeRPCRequest(r) + if err != nil { + http.Error(w, "bad request", http.StatusBadRequest) + return + } + + // Verify that the method is "eth_blockNumber". + if method, ok := req["method"].(string); !ok || method != "eth_blockNumber" { + http.Error(w, "unsupported method", http.StatusBadRequest) + return + } + + // Build and send a JSON–RPC response with block number 100 (hex "0x64"). + resp := map[string]interface{}{ + "jsonrpc": "2.0", + "id": req["id"], + "result": "0x64", + } + writeRPCResponse(w, resp) +} + +// errorRPCHandler simulates a failing RPC endpoint by returning status 500. +func errorRPCHandler(w http.ResponseWriter, r *http.Request) { + http.Error(w, "Internal Server Error", http.StatusInternalServerError) +} + +// delayedJSONRPCHandler returns a handler that simulates a delay and returns the given block number. +func delayedJSONRPCHandler(delay time.Duration, blockNumber uint64) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + // Simulate network delay. + time.Sleep(delay) + + req, err := decodeRPCRequest(r) + if err != nil { + http.Error(w, "bad request", http.StatusBadRequest) + return + } + + hexBlock := "0x" + strconv.FormatUint(blockNumber, 16) + resp := map[string]interface{}{ + "jsonrpc": "2.0", + "id": req["id"], + "result": hexBlock, + } + writeRPCResponse(w, resp) + } +} + +// makeHandler returns an HTTP handler that responds with the provided block number. +func makeHandler(blockNumber uint64) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + req, err := decodeRPCRequest(r) + if err != nil { + http.Error(w, "bad request", http.StatusBadRequest) + return + } + hexBlock := fmt.Sprintf("0x%x", blockNumber) + resp := map[string]interface{}{ + "jsonrpc": "2.0", + "id": req["id"], + "result": hexBlock, + } + writeRPCResponse(w, resp) + } +} + +// createManagerFromServers creates an RPCManager from a list of test servers. +func createManagerFromServers(servers ...*httptest.Server) *RPCManager { + endpoints := make([]*RPCEndpoint, len(servers)) + for i, s := range servers { + endpoints[i] = &RPCEndpoint{URL: s.URL} + } + return &RPCManager{Endpoints: endpoints} +} + +// TestRPCManagerWithJSONRPC verifies that RefreshEndpoints correctly pings multiple endpoints, +// updates their metrics, and selects the best (fastest healthy) endpoint. +func TestRPCManagerWithJSONRPC(t *testing.T) { + // Create three test servers: + // ts1: healthy with no artificial delay (using jsonRPCHandler which has block number 100 defined) + ts1 := httptest.NewServer(http.HandlerFunc(jsonRPCHandler)) + t.Cleanup(func() { ts1.Close() }) + + // ts2: healthy but with a 200ms delay (using delayedJSONRPCHandler returning block 100) + ts2 := httptest.NewServer(delayedJSONRPCHandler(200*time.Millisecond, 100)) + t.Cleanup(func() { ts2.Close() }) + + // ts3: unhealthy (using errorRPCHandler) + ts3 := httptest.NewServer(http.HandlerFunc(errorRPCHandler)) + t.Cleanup(func() { ts3.Close() }) + + // Create an RPCManager with all three endpoints. + manager := createManagerFromServers(ts1, ts2, ts3) + + // Refresh endpoints so that the manager pings each endpoint. + if err := manager.RefreshEndpoints(); err != nil { + t.Fatalf("RefreshEndpoints failed: %v", err) + } + + // Since ts1 and ts2 are healthy and return the same block number (100), + // the tie-breaker is latency. ts1 should be faster (no delay) than ts2. + bestURL, err := manager.GetBestEndpointURL() + if err != nil { + t.Fatalf("GetBestEndpointURL failed: %v", err) + } + + if bestURL != ts1.URL { + t.Errorf("Expected best endpoint to be %s, got %s", ts1.URL, bestURL) + } + + if manager.BestEndpoint.BlockNumber != 100 { + t.Errorf("Expected block number 100, got %d", manager.BestEndpoint.BlockNumber) + } + + if manager.BestEndpoint.Latency <= 0 { + t.Errorf("Expected positive latency, got %f", manager.BestEndpoint.Latency) + } +} + +// TestRPCManagerWithDelayedJSONRPC verifies that a delayed response is handled correctly, +// with latency measured properly and block number updated. +func TestRPCManagerWithDelayedJSONRPC(t *testing.T) { + delay := 2 * time.Second + blockNumber := uint64(150) + + ts := httptest.NewServer(delayedJSONRPCHandler(delay, blockNumber)) + t.Cleanup(func() { ts.Close() }) + + manager := &RPCManager{ + Endpoints: []*RPCEndpoint{ + {URL: ts.URL}, + }, + } + + start := time.Now() + if err := manager.RefreshEndpoints(); err != nil { + t.Fatalf("RefreshEndpoints failed: %v", err) + } + elapsed := time.Since(start) + if elapsed < delay { + t.Errorf("Expected elapsed time at least %v, got %v", delay, elapsed) + } + + bestURL, err := manager.GetBestEndpointURL() + if err != nil { + t.Fatalf("GetBestEndpointURL failed: %v", err) + } + if bestURL != ts.URL { + t.Errorf("Expected best endpoint URL %s, got %s", ts.URL, bestURL) + } + + if manager.BestEndpoint.BlockNumber != blockNumber { + t.Errorf("Expected block number %d, got %d", blockNumber, manager.BestEndpoint.BlockNumber) + } + + // Ensure the measured latency reflects the simulated delay. + if manager.BestEndpoint.Latency < delay.Seconds() { + t.Errorf("Expected measured latency at least %f, got %f", delay.Seconds(), manager.BestEndpoint.Latency) + } +} + +// TestSwitchToNextBestClient verifies the behavior of SwitchToNextBestRPCClient under various conditions. +func TestSwitchToNextBestClient(t *testing.T) { + t.Run("switches when best endpoint fails", func(t *testing.T) { + // Create three test servers with different block numbers. + ts1 := httptest.NewServer(makeHandler(100)) + t.Cleanup(func() { ts1.Close() }) + + ts2 := httptest.NewServer(makeHandler(120)) + // Do not defer ts2.Close() here to simulate its failure. + + ts3 := httptest.NewServer(makeHandler(110)) + t.Cleanup(func() { ts3.Close() }) + + manager := createManagerFromServers(ts1, ts2, ts3) + + if err := manager.RefreshEndpoints(); err != nil { + t.Fatalf("RefreshEndpoints failed: %v", err) + } + + bestURL, err := manager.GetBestEndpointURL() + if err != nil { + t.Fatalf("GetBestEndpointURL failed: %v", err) + } + if bestURL != ts2.URL { + t.Fatalf("Expected best endpoint to be %s, got %s", ts2.URL, bestURL) + } + + // Simulate failure of the best endpoint. + ts2.Close() + time.Sleep(100 * time.Millisecond) + + switched, err := manager.SwitchToNextBestRPCClient() + if err != nil { + t.Fatalf("SwitchToNextBestRPCClient returned error: %v", err) + } + if !switched { + t.Fatal("Expected switch to next best endpoint, but no switch occurred") + } + + newBestURL, err := manager.GetBestEndpointURL() + if err != nil { + t.Fatalf("GetBestEndpointURL failed after switch: %v", err) + } + if newBestURL != ts3.URL { + t.Errorf("Expected new best endpoint to be %s, got %s", ts3.URL, newBestURL) + } + if manager.BestEndpoint.BlockNumber != 110 { + t.Errorf("Expected block number 110 for new best endpoint, got %d", manager.BestEndpoint.BlockNumber) + } + }) + + t.Run("does not switch when the rest of the endpoints are not healthy", func(t *testing.T) { + ts1 := httptest.NewServer(makeHandler(100)) + ts2 := httptest.NewServer(makeHandler(120)) + ts3 := httptest.NewServer(makeHandler(110)) + t.Cleanup(func() { ts1.Close() }) + t.Cleanup(func() { ts2.Close() }) + t.Cleanup(func() { ts3.Close() }) + + manager := createManagerFromServers(ts1, ts2, ts3) + + if err := manager.RefreshEndpoints(); err != nil { + t.Fatalf("RefreshEndpoints failed: %v", err) + } + + bestURL, err := manager.GetBestEndpointURL() + if err != nil { + t.Fatalf("GetBestEndpointURL failed: %v", err) + } + if bestURL != ts2.URL { + t.Fatalf("Expected best endpoint to be %s, got %s", ts2.URL, bestURL) + } + + // Simulate failure of ts1 and ts3. + ts1.Close() + ts3.Close() + time.Sleep(100 * time.Millisecond) + + switched, err := manager.SwitchToNextBestRPCClient() + if err != nil { + t.Fatalf("SwitchToNextBestRPCClient returned error: %v", err) + } + if switched { + t.Error("Did not expect a switch when the alternative endpoints are unhealthy") + } + + newBestURL, err := manager.GetBestEndpointURL() + if err != nil { + t.Fatalf("GetBestEndpointURL failed after attempted switch: %v", err) + } + if newBestURL != ts2.URL { + t.Errorf("Expected best endpoint to remain %s, got %s", ts2.URL, newBestURL) + } + }) + + t.Run("returns false when only one endpoint is available", func(t *testing.T) { + ts1 := httptest.NewServer(makeHandler(120)) + t.Cleanup(func() { ts1.Close() }) + + manager := createManagerFromServers(ts1) + if err := manager.RefreshEndpoints(); err != nil { + t.Fatalf("RefreshEndpoints failed: %v", err) + } + + switched, err := manager.SwitchToNextBestRPCClient() + if err != nil { + t.Fatalf("SwitchToNextBestRPCClient returned error: %v", err) + } + if switched { + t.Error("Expected no switch when only one endpoint is available") + } + }) + + t.Run("returns error when current best client is not found in the list", func(t *testing.T) { + ts1 := httptest.NewServer(makeHandler(100)) + ts2 := httptest.NewServer(makeHandler(120)) + t.Cleanup(func() { ts1.Close() }) + t.Cleanup(func() { ts2.Close() }) + + manager := createManagerFromServers(ts1, ts2) + if err := manager.RefreshEndpoints(); err != nil { + t.Fatalf("RefreshEndpoints failed: %v", err) + } + + // Simulate a scenario where the current best client is not in the endpoints list. + manager.BestEndpoint = &RPCEndpoint{URL: "http://nonexistent"} + _, err := manager.SwitchToNextBestRPCClient() + if err == nil { + t.Error("Expected an error when current best client is not found, but got nil") + } + }) +} From ce4180e59be9d717af60b2e9a7174db5cbb0f646 Mon Sep 17 00:00:00 2001 From: Yashk767 <76935991+Yashk767@users.noreply.github.com> Date: Thu, 27 Feb 2025 21:09:26 +0530 Subject: [PATCH 3/9] fix: switch RPC if block number is less than last recorded block number (#1264) * fix: switch RPC if block number is less than last recorded block number * refactor: added tests for block module --- block/block.go | 20 ++++ block/block_test.go | 240 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 260 insertions(+) create mode 100644 block/block_test.go diff --git a/block/block.go b/block/block.go index 08782e45..719f1cd5 100644 --- a/block/block.go +++ b/block/block.go @@ -64,6 +64,26 @@ func (bm *BlockMonitor) updateLatestBlock() { bm.mu.Lock() defer bm.mu.Unlock() + // Check if the fetched block number is less than the last recorded block number. + if bm.latestBlock != nil && header.Number.Uint64() < bm.latestBlock.Number.Uint64() { + logrus.Warnf("Fetched block number %d is less than the last recorded block number %d. Switching to the next best RPC endpoint.", + header.Number.Uint64(), bm.latestBlock.Number.Uint64()) + + // Attempt to switch to the next best RPC endpoint. + if bm.rpcManager != nil { + switched, err := bm.rpcManager.SwitchToNextBestRPCClient() + if err != nil { + logrus.Errorf("Failed to switch RPC endpoint: %v", err) + } else if switched { + logrus.Info("Switched to the next best RPC endpoint.") + bm.updateClient() + } else { + logrus.Warn("Retaining the current best RPC endpoint as no valid alternate was found.") + } + } + return + } + // Update the latest block only if it changes. if bm.latestBlock == nil || header.Number.Uint64() != bm.latestBlock.Number.Uint64() { bm.latestBlock = header diff --git a/block/block_test.go b/block/block_test.go new file mode 100644 index 00000000..15daf8df --- /dev/null +++ b/block/block_test.go @@ -0,0 +1,240 @@ +package block + +import ( + "encoding/json" + "fmt" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "math/big" + "net/http" + "net/http/httptest" + "sync/atomic" + "testing" + "time" + + "razor/rpc" +) + +func makeBlockHandler(blockNumber uint64, blockTime uint64) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req map[string]interface{} + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "bad request", http.StatusBadRequest) + return + } + + method, ok := req["method"].(string) + if !ok { + http.Error(w, "missing method", http.StatusBadRequest) + return + } + + var result interface{} + + switch method { + case "eth_blockNumber": + result = fmt.Sprintf("0x%x", blockNumber) + + case "eth_getBlockByNumber": + // Use go-ethereum's types.Header struct to ensure all required fields are included + header := &types.Header{ + Number: big.NewInt(int64(blockNumber)), + Time: blockTime, + ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), + UncleHash: types.EmptyUncleHash, + Coinbase: common.HexToAddress("0x0000000000000000000000000000000000000000"), + Root: common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222"), + TxHash: common.HexToHash("0x3333333333333333333333333333333333333333333333333333333333333333"), + ReceiptHash: common.HexToHash("0x4444444444444444444444444444444444444444444444444444444444444444"), + Bloom: types.Bloom{}, + Difficulty: big.NewInt(2), + GasLimit: 30000000, + GasUsed: 0, + Extra: []byte{}, + } + + // Serialize the header to JSON format + result = header + default: + http.Error(w, "unsupported method", http.StatusBadRequest) + return + } + + resp := map[string]interface{}{ + "jsonrpc": "2.0", + "id": req["id"], + "result": result, + } + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(resp) + } +} + +// createManagerFromServers creates an RPCManager from a list of test servers. +func createManagerFromServers(servers ...*httptest.Server) *rpc.RPCManager { + endpoints := make([]*rpc.RPCEndpoint, len(servers)) + for i, s := range servers { + endpoints[i] = &rpc.RPCEndpoint{URL: s.URL} + } + return &rpc.RPCManager{Endpoints: endpoints} +} + +// TestBlockMonitorUpdateBlock tests `updateLatestBlock` behavior with different block numbers. +func TestBlockMonitorUpdateBlock(t *testing.T) { + // Simulate two endpoints: one returning an outdated block, another returning an up-to-date block. + blockNumber := uint64(100) + outdatedBlockNumber := uint64(90) + + ts1 := httptest.NewServer(makeBlockHandler(blockNumber, uint64(time.Now().Unix()))) + t.Cleanup(func() { ts1.Close() }) + + ts2 := httptest.NewServer(makeBlockHandler(outdatedBlockNumber, uint64(time.Now().Unix()))) + t.Cleanup(func() { ts2.Close() }) + + // Create an RPC manager with both endpoints. + manager := createManagerFromServers(ts1, ts2) + + // Refresh endpoints so that the manager pings each endpoint. + if err := manager.RefreshEndpoints(); err != nil { + t.Fatalf("RefreshEndpoints failed: %v", err) + } + + // Initialize BlockMonitor. + client, _ := manager.GetBestRPCClient() + bm := NewBlockMonitor(client, manager, 1, 10) + + // Simulate fetching the latest block. + bm.updateLatestBlock() + + if bm.latestBlock == nil { + t.Fatal("Expected latest block to be set, but got nil") + } + + // Ensure that the latest block number is from the correct, up-to-date endpoint. + if bm.latestBlock.Number.Uint64() != blockNumber { + t.Errorf("Expected block number %d, got %d", blockNumber, bm.latestBlock.Number.Uint64()) + } + + // Simulate outdated block number being reported. + bm.latestBlock.Number = big.NewInt(int64(outdatedBlockNumber)) + bm.updateLatestBlock() + + // The block number should remain at the latest, and an RPC switch should have occurred. + newBestURL, _ := manager.GetBestEndpointURL() + if newBestURL != ts1.URL { + t.Errorf("Expected best endpoint to be %s after outdated block, got %s", ts1.URL, newBestURL) + } +} + +// TestBlockMonitorStaleBlock checks if the stale block detection works correctly. +func TestBlockMonitorStaleBlock(t *testing.T) { + currentTime := uint64(time.Now().Unix()) + staleTime := uint64(time.Now().Add(-15 * time.Second).Unix()) + + ts1 := httptest.NewServer(makeBlockHandler(120, currentTime)) + t.Cleanup(func() { ts1.Close() }) + + ts2 := httptest.NewServer(makeBlockHandler(110, staleTime)) + t.Cleanup(func() { ts2.Close() }) + + // Create an RPC manager with both endpoints. + manager := createManagerFromServers(ts1, ts2) + + // Refresh endpoints so that the manager pings each endpoint. + if err := manager.RefreshEndpoints(); err != nil { + t.Fatalf("RefreshEndpoints failed: %v", err) + } + + // Initialize BlockMonitor. + client, _ := manager.GetBestRPCClient() + bm := NewBlockMonitor(client, manager, 1, 10) + + // Fetch the latest block (stale one) + bm.updateLatestBlock() + bm.checkForStaleBlock() + + if bm.latestBlock.Number.Uint64() != 120 { + t.Errorf("Expected block number 120 after detecting stale block, got %d", bm.latestBlock.Number.Uint64()) + } +} + +// TestBlockMonitorSwitchOnStale tests switching to a better endpoint when a stale block is detected. +func TestBlockMonitorSwitchOnStale(t *testing.T) { + latestBlock := uint64(150) + staleBlock := uint64(140) + + var blockNumber atomic.Uint64 + blockNumber.Store(staleBlock) + + // Simulate a server that starts with a stale block but updates to a fresh block. + ts1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + makeBlockHandler(blockNumber.Load(), uint64(time.Now().Unix()))(w, r) + })) + t.Cleanup(func() { ts1.Close() }) + + ts2 := httptest.NewServer(makeBlockHandler(latestBlock, uint64(time.Now().Unix()))) + t.Cleanup(func() { ts2.Close() }) + + // Create an RPC manager. + manager := createManagerFromServers(ts1, ts2) + + // Refresh endpoints so that the manager pings each endpoint. + if err := manager.RefreshEndpoints(); err != nil { + t.Fatalf("RefreshEndpoints failed: %v", err) + } + + // Initialize BlockMonitor. + client, _ := manager.GetBestRPCClient() + bm := NewBlockMonitor(client, manager, 1, 10) + + // Start with a stale block. + blockNumber.Store(staleBlock) + bm.updateLatestBlock() + bm.checkForStaleBlock() + + // Ensure the switch occurred to the better endpoint. + bestURL, _ := manager.GetBestEndpointURL() + if bestURL != ts2.URL { + t.Errorf("Expected best endpoint to switch to %s, got %s", ts2.URL, bestURL) + } + + // Now update the first endpoint to a fresh block. + blockNumber.Store(latestBlock) + bm.updateLatestBlock() + bm.checkForStaleBlock() + + // The monitor should detect the updated block. + if bm.latestBlock.Number.Uint64() != latestBlock { + t.Errorf("Expected latest block number %d, got %d", latestBlock, bm.latestBlock.Number.Uint64()) + } +} + +// TestBlockMonitorSwitchFailure tests when no alternate endpoints are available. +func TestBlockMonitorSwitchFailure(t *testing.T) { + staleBlock := uint64(80) + + ts1 := httptest.NewServer(makeBlockHandler(staleBlock, uint64(time.Now().Add(-20*time.Second).Unix()))) + t.Cleanup(func() { ts1.Close() }) + + // Create an RPC manager with a single stale endpoint. + manager := createManagerFromServers(ts1) + + // Refresh endpoints so that the manager pings each endpoint. + if err := manager.RefreshEndpoints(); err != nil { + t.Fatalf("RefreshEndpoints failed: %v", err) + } + + // Initialize BlockMonitor. + client, _ := manager.GetBestRPCClient() + bm := NewBlockMonitor(client, manager, 1, 10) + + // Start with a stale block. + bm.updateLatestBlock() + bm.checkForStaleBlock() + + // Since no alternate endpoints are available, the best endpoint should remain unchanged. + bestURL, _ := manager.GetBestEndpointURL() + if bestURL != ts1.URL { + t.Errorf("Expected best endpoint to remain %s, got %s", ts1.URL, bestURL) + } +} From 96f1e2842c65073ac6671685c7dd0e9380975c5b Mon Sep 17 00:00:00 2001 From: Yashk767 <76935991+Yashk767@users.noreply.github.com> Date: Fri, 28 Feb 2025 12:24:04 +0530 Subject: [PATCH 4/9] refactor: fetched block number from block monitor module in voting process (#1269) * refactor: fetched block number from block monitor in voting * refactor: fixed tests * fix: added nil check for header from block monitor * refactor: replaced empty block monitor reference with nil in case of error --- cmd/addStake.go | 2 +- cmd/claimBounty.go | 2 +- cmd/claimCommission.go | 2 +- cmd/cmd-utils.go | 16 ++++++++-------- cmd/collectionList.go | 2 +- cmd/contractAddresses.go | 2 +- cmd/create.go | 2 +- cmd/createCollection.go | 2 +- cmd/createJob.go | 2 +- cmd/delegate.go | 2 +- cmd/import.go | 2 +- cmd/initiateWithdraw.go | 2 +- cmd/interface.go | 3 ++- cmd/jobList.go | 2 +- cmd/mocks/utils_cmd_interface.go | 9 +++++---- cmd/modifyCollectionStatus.go | 2 +- cmd/resetUnstakeLock.go | 2 +- cmd/setConfig.go | 2 +- cmd/setDelegation.go | 2 +- cmd/stakerInfo.go | 2 +- cmd/transfer.go | 2 +- cmd/unlockWithdraw.go | 2 +- cmd/unstake.go | 2 +- cmd/updateCollection.go | 2 +- cmd/updateCommission.go | 2 +- cmd/updateJob.go | 2 +- cmd/vote.go | 13 +++++++------ cmd/vote_test.go | 12 ++++-------- 28 files changed, 49 insertions(+), 50 deletions(-) diff --git a/cmd/addStake.go b/cmd/addStake.go index a32c4425..c80445ec 100644 --- a/cmd/addStake.go +++ b/cmd/addStake.go @@ -32,7 +32,7 @@ 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, rpcParameters, account, err := InitializeCommandDependencies(flagSet) + config, rpcParameters, _, account, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) balance, err := razorUtils.FetchBalance(rpcParameters, account.Address) diff --git a/cmd/claimBounty.go b/cmd/claimBounty.go index 16d23fc8..9d4faaf0 100644 --- a/cmd/claimBounty.go +++ b/cmd/claimBounty.go @@ -34,7 +34,7 @@ func initialiseClaimBounty(cmd *cobra.Command, args []string) { //This function sets the flags appropriately and executes the ClaimBounty function func (*UtilsStruct) ExecuteClaimBounty(flagSet *pflag.FlagSet) { - config, rpcParameters, account, err := InitializeCommandDependencies(flagSet) + config, rpcParameters, _, account, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) if razorUtils.IsFlagPassed("bountyId") { diff --git a/cmd/claimCommission.go b/cmd/claimCommission.go index 5930596d..391e203a 100644 --- a/cmd/claimCommission.go +++ b/cmd/claimCommission.go @@ -26,7 +26,7 @@ Example: //This function allows the staker to claim the rewards earned from delegator's pool share as commission func (*UtilsStruct) ClaimCommission(flagSet *pflag.FlagSet) { - config, rpcParameters, account, err := InitializeCommandDependencies(flagSet) + config, rpcParameters, _, account, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) stakerId, err := razorUtils.GetStakerId(rpcParameters, account.Address) diff --git a/cmd/cmd-utils.go b/cmd/cmd-utils.go index 7b3462e3..7f1fb8d2 100644 --- a/cmd/cmd-utils.go +++ b/cmd/cmd-utils.go @@ -130,7 +130,7 @@ func GetFormattedStateNames(states []int) string { return statesAllowed } -func InitializeCommandDependencies(flagSet *pflag.FlagSet) (types.Configurations, rpc.RPCParameters, types.Account, error) { +func InitializeCommandDependencies(flagSet *pflag.FlagSet) (types.Configurations, rpc.RPCParameters, *block.BlockMonitor, types.Account, error) { var ( account types.Account client *ethclient.Client @@ -141,7 +141,7 @@ func InitializeCommandDependencies(flagSet *pflag.FlagSet) (types.Configurations config, err := cmdUtils.GetConfigData() if err != nil { log.Error("Error in getting config: ", err) - return types.Configurations{}, rpc.RPCParameters{}, types.Account{}, err + return types.Configurations{}, rpc.RPCParameters{}, nil, types.Account{}, err } log.Debugf("Config: %+v", config) @@ -149,7 +149,7 @@ func InitializeCommandDependencies(flagSet *pflag.FlagSet) (types.Configurations address, err := flagSetUtils.GetStringAddress(flagSet) if err != nil { log.Error("Error in getting address: ", err) - return types.Configurations{}, rpc.RPCParameters{}, types.Account{}, err + return types.Configurations{}, rpc.RPCParameters{}, nil, types.Account{}, err } log.Debugf("Address: %v", address) @@ -159,21 +159,21 @@ func InitializeCommandDependencies(flagSet *pflag.FlagSet) (types.Configurations accountManager, err := razorUtils.AccountManagerForKeystore() if err != nil { log.Error("Error in getting accounts manager for keystore: ", err) - return types.Configurations{}, rpc.RPCParameters{}, types.Account{}, err + return types.Configurations{}, rpc.RPCParameters{}, nil, types.Account{}, err } account = accounts.InitAccountStruct(address, password, accountManager) err = razorUtils.CheckPassword(account) if err != nil { log.Error("Error in fetching private key from given password: ", err) - return types.Configurations{}, rpc.RPCParameters{}, types.Account{}, err + return types.Configurations{}, rpc.RPCParameters{}, nil, types.Account{}, err } } rpcManager, err := rpc.InitializeRPCManager(config.Provider) if err != nil { log.Error("Error in initializing RPC Manager: ", err) - return types.Configurations{}, rpc.RPCParameters{}, types.Account{}, err + return types.Configurations{}, rpc.RPCParameters{}, nil, types.Account{}, err } rpcParameters = rpc.RPCParameters{ @@ -184,7 +184,7 @@ func InitializeCommandDependencies(flagSet *pflag.FlagSet) (types.Configurations client, err = rpcManager.GetBestRPCClient() if err != nil { log.Error("Error in getting best RPC client: ", err) - return types.Configurations{}, rpc.RPCParameters{}, types.Account{}, err + return types.Configurations{}, rpc.RPCParameters{}, nil, types.Account{}, err } // Initialize BlockMonitor with RPCManager @@ -196,5 +196,5 @@ func InitializeCommandDependencies(flagSet *pflag.FlagSet) (types.Configurations // Update Logger Instance logger.UpdateLogger(account.Address, client, blockMonitor) - return config, rpcParameters, account, nil + return config, rpcParameters, blockMonitor, account, nil } diff --git a/cmd/collectionList.go b/cmd/collectionList.go index 4e94ffc4..afee6cc7 100644 --- a/cmd/collectionList.go +++ b/cmd/collectionList.go @@ -31,7 +31,7 @@ func initialiseCollectionList(cmd *cobra.Command, args []string) { //This function sets the flags appropriately and and executes the GetCollectionList function func (*UtilsStruct) ExecuteCollectionList(flagSet *pflag.FlagSet) { - _, rpcParameters, _, err := InitializeCommandDependencies(flagSet) + _, rpcParameters, _, _, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) log.Debug("Calling GetCollectionList()") diff --git a/cmd/contractAddresses.go b/cmd/contractAddresses.go index 614fae1b..b3878b7c 100644 --- a/cmd/contractAddresses.go +++ b/cmd/contractAddresses.go @@ -25,7 +25,7 @@ func initialiseContractAddresses(cmd *cobra.Command, args []string) { //This function sets the flag appropriatley and executes the ContractAddresses function func (*UtilsStruct) ExecuteContractAddresses(flagSet *pflag.FlagSet) { - _, _, _, err := InitializeCommandDependencies(flagSet) + _, _, _, _, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) fmt.Println("The contract addresses are: ") diff --git a/cmd/create.go b/cmd/create.go index da907116..8e0bde8b 100644 --- a/cmd/create.go +++ b/cmd/create.go @@ -28,7 +28,7 @@ func initialiseCreate(cmd *cobra.Command, args []string) { //This function sets the flags appropriately and executes the Create function func (*UtilsStruct) ExecuteCreate(flagSet *pflag.FlagSet) { - _, _, _, err := InitializeCommandDependencies(flagSet) + _, _, _, _, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) log.Info("The password should be of minimum 8 characters containing least 1 uppercase, lowercase, digit and special character.") password := razorUtils.AssignPassword(flagSet) diff --git a/cmd/createCollection.go b/cmd/createCollection.go index c7067c5f..6c27c1e9 100644 --- a/cmd/createCollection.go +++ b/cmd/createCollection.go @@ -34,7 +34,7 @@ func initialiseCreateCollection(cmd *cobra.Command, args []string) { //This function sets the flags appropriately and executes the CreateCollection function func (*UtilsStruct) ExecuteCreateCollection(flagSet *pflag.FlagSet) { - config, rpcParameters, account, err := InitializeCommandDependencies(flagSet) + config, rpcParameters, _, account, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) name, err := flagSetUtils.GetStringName(flagSet) diff --git a/cmd/createJob.go b/cmd/createJob.go index 68b320ab..36b70896 100644 --- a/cmd/createJob.go +++ b/cmd/createJob.go @@ -35,7 +35,7 @@ func initialiseCreateJob(cmd *cobra.Command, args []string) { //This function sets the flags appropriately and executes the CreateJob function func (*UtilsStruct) ExecuteCreateJob(flagSet *pflag.FlagSet) { - config, rpcParameters, account, err := InitializeCommandDependencies(flagSet) + config, rpcParameters, _, account, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) name, err := flagSetUtils.GetStringName(flagSet) diff --git a/cmd/delegate.go b/cmd/delegate.go index 49a49aca..eb899159 100644 --- a/cmd/delegate.go +++ b/cmd/delegate.go @@ -32,7 +32,7 @@ func initialiseDelegate(cmd *cobra.Command, args []string) { //This function sets the flags appropriately and executes the Delegate function func (*UtilsStruct) ExecuteDelegate(flagSet *pflag.FlagSet) { - config, rpcParameters, account, err := InitializeCommandDependencies(flagSet) + config, rpcParameters, _, account, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) stakerId, err := flagSetUtils.GetUint32StakerId(flagSet) diff --git a/cmd/import.go b/cmd/import.go index ddb722ff..4970b6dc 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -29,7 +29,7 @@ func initialiseImport(cmd *cobra.Command, args []string) { //This function sets the flags appropriately and executes the ImportAccount function func (*UtilsStruct) ExecuteImport(flagSet *pflag.FlagSet) { - _, _, _, err := InitializeCommandDependencies(flagSet) + _, _, _, _, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) log.Debug("Calling ImportAccount()...") account, err := cmdUtils.ImportAccount() diff --git a/cmd/initiateWithdraw.go b/cmd/initiateWithdraw.go index 36a095d2..afaabab2 100644 --- a/cmd/initiateWithdraw.go +++ b/cmd/initiateWithdraw.go @@ -31,7 +31,7 @@ Example: //This function sets the flags appropriately and executes the InitiateWithdraw function func (*UtilsStruct) ExecuteInitiateWithdraw(flagSet *pflag.FlagSet) { - config, rpcParameters, account, err := InitializeCommandDependencies(flagSet) + config, rpcParameters, _, account, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) stakerId, err := razorUtils.AssignStakerId(rpcParameters, flagSet, account.Address) diff --git a/cmd/interface.go b/cmd/interface.go index f57f13a1..16c6ee2c 100644 --- a/cmd/interface.go +++ b/cmd/interface.go @@ -4,6 +4,7 @@ package cmd import ( "crypto/ecdsa" "math/big" + "razor/block" "razor/cache" "razor/core/types" "razor/path" @@ -225,7 +226,7 @@ type UtilsCmdInterface interface { CalculateSecret(account types.Account, epoch uint32, keystorePath string, chainId *big.Int) ([]byte, []byte, error) HandleBlock(rpcParameters rpc.RPCParameters, account types.Account, stakerId uint32, header *Types.Header, config types.Configurations, commitParams *types.CommitParams, rogueData types.Rogue, backupNodeActionsToIgnore []string) ExecuteVote(flagSet *pflag.FlagSet) - Vote(rpcParameters rpc.RPCParameters, config types.Configurations, account types.Account, stakerId uint32, commitParams *types.CommitParams, rogueData types.Rogue, backupNodeActionsToIgnore []string) error + Vote(rpcParameters rpc.RPCParameters, blockMonitor *block.BlockMonitor, config types.Configurations, account types.Account, stakerId uint32, commitParams *types.CommitParams, rogueData types.Rogue, backupNodeActionsToIgnore []string) error HandleExit() ExecuteListAccounts(flagSet *pflag.FlagSet) ClaimCommission(flagSet *pflag.FlagSet) diff --git a/cmd/jobList.go b/cmd/jobList.go index ea8acc0d..e1144718 100644 --- a/cmd/jobList.go +++ b/cmd/jobList.go @@ -29,7 +29,7 @@ func initialiseJobList(cmd *cobra.Command, args []string) { //This function sets the flags appropriately and executes the GetJobList function func (*UtilsStruct) ExecuteJobList(flagSet *pflag.FlagSet) { - _, rpcParameters, _, err := InitializeCommandDependencies(flagSet) + _, rpcParameters, _, _, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) log.Debug("ExecuteJobList: Calling JobList()...") diff --git a/cmd/mocks/utils_cmd_interface.go b/cmd/mocks/utils_cmd_interface.go index a3841765..7a7317ec 100644 --- a/cmd/mocks/utils_cmd_interface.go +++ b/cmd/mocks/utils_cmd_interface.go @@ -4,6 +4,7 @@ package mocks import ( big "math/big" + "razor/block" RPC "razor/rpc" accounts "github.com/ethereum/go-ethereum/accounts" @@ -1853,12 +1854,12 @@ func (_m *UtilsCmdInterface) UpdateJob(rpcParameters RPC.RPCParameters, config t } // Vote provides a mock function with given fields: rpcParameters, config, account, stakerId, commitParams, rogueData, backupNodeActionsToIgnore -func (_m *UtilsCmdInterface) Vote(rpcParameters RPC.RPCParameters, config types.Configurations, account types.Account, stakerId uint32, commitParams *types.CommitParams, rogueData types.Rogue, backupNodeActionsToIgnore []string) error { - ret := _m.Called(rpcParameters, config, account, stakerId, commitParams, rogueData, backupNodeActionsToIgnore) +func (_m *UtilsCmdInterface) Vote(rpcParameters RPC.RPCParameters, blockMonitor *block.BlockMonitor, config types.Configurations, account types.Account, stakerId uint32, commitParams *types.CommitParams, rogueData types.Rogue, backupNodeActionsToIgnore []string) error { + ret := _m.Called(rpcParameters, blockMonitor, config, account, stakerId, commitParams, rogueData, backupNodeActionsToIgnore) var r0 error - if rf, ok := ret.Get(0).(func(RPC.RPCParameters, types.Configurations, types.Account, uint32, *types.CommitParams, types.Rogue, []string) error); ok { - r0 = rf(rpcParameters, config, account, stakerId, commitParams, rogueData, backupNodeActionsToIgnore) + if rf, ok := ret.Get(0).(func(RPC.RPCParameters, *block.BlockMonitor, types.Configurations, types.Account, uint32, *types.CommitParams, types.Rogue, []string) error); ok { + r0 = rf(rpcParameters, blockMonitor, config, account, stakerId, commitParams, rogueData, backupNodeActionsToIgnore) } else { r0 = ret.Error(0) } diff --git a/cmd/modifyCollectionStatus.go b/cmd/modifyCollectionStatus.go index a9119444..e6b4d1be 100644 --- a/cmd/modifyCollectionStatus.go +++ b/cmd/modifyCollectionStatus.go @@ -29,7 +29,7 @@ func initialiseModifyCollectionStatus(cmd *cobra.Command, args []string) { //This function sets the flags appropriately and executes the ModifyCollectionStatus function func (*UtilsStruct) ExecuteModifyCollectionStatus(flagSet *pflag.FlagSet) { - config, rpcParameters, account, err := InitializeCommandDependencies(flagSet) + config, rpcParameters, _, account, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) collectionId, err := flagSetUtils.GetUint16CollectionId(flagSet) diff --git a/cmd/resetUnstakeLock.go b/cmd/resetUnstakeLock.go index 9f594a55..c71f5829 100644 --- a/cmd/resetUnstakeLock.go +++ b/cmd/resetUnstakeLock.go @@ -32,7 +32,7 @@ func initialiseExtendLock(cmd *cobra.Command, args []string) { //This function sets the flags appropriately and executes the ResetUnstakeLock function func (*UtilsStruct) ExecuteExtendLock(flagSet *pflag.FlagSet) { - config, rpcParameters, account, err := InitializeCommandDependencies(flagSet) + config, rpcParameters, _, account, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) stakerId, err := razorUtils.AssignStakerId(rpcParameters, flagSet, account.Address) diff --git a/cmd/setConfig.go b/cmd/setConfig.go index 9f4b7d89..1927b5ef 100644 --- a/cmd/setConfig.go +++ b/cmd/setConfig.go @@ -29,7 +29,7 @@ Example: // This function returns the error if there is any and sets the config func (*UtilsStruct) SetConfig(flagSet *pflag.FlagSet) error { - _, _, _, err := InitializeCommandDependencies(flagSet) + _, _, _, _, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) flagDetails := []types.FlagDetail{ diff --git a/cmd/setDelegation.go b/cmd/setDelegation.go index 690cd63a..338e5765 100644 --- a/cmd/setDelegation.go +++ b/cmd/setDelegation.go @@ -32,7 +32,7 @@ func initialiseSetDelegation(cmd *cobra.Command, args []string) { //This function sets the flags appropriately and executes the SetDelegation function func (*UtilsStruct) ExecuteSetDelegation(flagSet *pflag.FlagSet) { - config, rpcParameters, account, err := InitializeCommandDependencies(flagSet) + config, rpcParameters, _, account, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) statusString, err := flagSetUtils.GetStringStatus(flagSet) diff --git a/cmd/stakerInfo.go b/cmd/stakerInfo.go index 919c2dbb..364c7c9d 100644 --- a/cmd/stakerInfo.go +++ b/cmd/stakerInfo.go @@ -28,7 +28,7 @@ func initialiseStakerInfo(cmd *cobra.Command, args []string) { //This function sets the flag appropriately and executes the GetStakerInfo function func (*UtilsStruct) ExecuteStakerinfo(flagSet *pflag.FlagSet) { - _, rpcParameters, _, err := InitializeCommandDependencies(flagSet) + _, rpcParameters, _, _, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) stakerId, err := flagSetUtils.GetUint32StakerId(flagSet) diff --git a/cmd/transfer.go b/cmd/transfer.go index 24c1e71a..c1c44c16 100644 --- a/cmd/transfer.go +++ b/cmd/transfer.go @@ -32,7 +32,7 @@ func initialiseTransfer(cmd *cobra.Command, args []string) { //This function sets the flag appropriately and executes the Transfer function func (*UtilsStruct) ExecuteTransfer(flagSet *pflag.FlagSet) { - config, rpcParameters, _, err := InitializeCommandDependencies(flagSet) + config, rpcParameters, _, _, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) log.Debugf("ExecuteTransfer: Config: %+v", config) diff --git a/cmd/unlockWithdraw.go b/cmd/unlockWithdraw.go index 1081a16c..25f67059 100644 --- a/cmd/unlockWithdraw.go +++ b/cmd/unlockWithdraw.go @@ -31,7 +31,7 @@ func initializeUnlockWithdraw(cmd *cobra.Command, args []string) { //This function sets the flag appropriately and executes the UnlockWithdraw function func (*UtilsStruct) ExecuteUnlockWithdraw(flagSet *pflag.FlagSet) { - config, rpcParameters, account, err := InitializeCommandDependencies(flagSet) + config, rpcParameters, _, account, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) stakerId, err := razorUtils.AssignStakerId(rpcParameters, flagSet, account.Address) diff --git a/cmd/unstake.go b/cmd/unstake.go index 4b9c52d6..e390ca5c 100644 --- a/cmd/unstake.go +++ b/cmd/unstake.go @@ -35,7 +35,7 @@ func initialiseUnstake(cmd *cobra.Command, args []string) { //This function sets the flag appropriately and executes the Unstake function func (*UtilsStruct) ExecuteUnstake(flagSet *pflag.FlagSet) { - config, rpcParameters, account, err := InitializeCommandDependencies(flagSet) + config, rpcParameters, _, account, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) log.Debug("Getting amount in wei...") diff --git a/cmd/updateCollection.go b/cmd/updateCollection.go index d9896aaa..03a57e7d 100644 --- a/cmd/updateCollection.go +++ b/cmd/updateCollection.go @@ -34,7 +34,7 @@ func initialiseUpdateCollection(cmd *cobra.Command, args []string) { //This function sets the flag appropriately and executes the UpdateCollection function func (*UtilsStruct) ExecuteUpdateCollection(flagSet *pflag.FlagSet) { - config, rpcParameters, account, err := InitializeCommandDependencies(flagSet) + config, rpcParameters, _, account, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) collectionId, err := flagSetUtils.GetUint16CollectionId(flagSet) diff --git a/cmd/updateCommission.go b/cmd/updateCommission.go index 548b15aa..ba7142c8 100644 --- a/cmd/updateCommission.go +++ b/cmd/updateCommission.go @@ -31,7 +31,7 @@ func initialiseUpdateCommission(cmd *cobra.Command, args []string) { //This function sets the flag appropriately and executes the UpdateCommission function func (*UtilsStruct) ExecuteUpdateCommission(flagSet *pflag.FlagSet) { - config, rpcParameters, account, err := InitializeCommandDependencies(flagSet) + config, rpcParameters, _, account, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) commission, err := flagSetUtils.GetUint8Commission(flagSet) diff --git a/cmd/updateJob.go b/cmd/updateJob.go index 4bd06223..d4c24dd4 100644 --- a/cmd/updateJob.go +++ b/cmd/updateJob.go @@ -34,7 +34,7 @@ func initialiseUpdateJob(cmd *cobra.Command, args []string) { //This function sets the flag appropriately and executes the UpdateJob function func (*UtilsStruct) ExecuteUpdateJob(flagSet *pflag.FlagSet) { - config, rpcParameters, account, err := InitializeCommandDependencies(flagSet) + config, rpcParameters, _, account, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) jobId, err := flagSetUtils.GetUint16JobId(flagSet) diff --git a/cmd/vote.go b/cmd/vote.go index f5fff9ad..608b7e2a 100644 --- a/cmd/vote.go +++ b/cmd/vote.go @@ -10,6 +10,7 @@ import ( "os" "os/signal" "path/filepath" + "razor/block" "razor/cache" "razor/core" "razor/core/types" @@ -46,7 +47,7 @@ func initializeVote(cmd *cobra.Command, args []string) { //This function sets the flag appropriately and executes the Vote function func (*UtilsStruct) ExecuteVote(flagSet *pflag.FlagSet) { - config, rpcParameters, account, err := InitializeCommandDependencies(flagSet) + config, rpcParameters, blockMonitor, account, err := InitializeCommandDependencies(flagSet) utils.CheckError("Error in initialising command dependencies: ", err) err = ValidateBufferPercentLimit(rpcParameters, config.BufferPercent) @@ -102,7 +103,7 @@ func (*UtilsStruct) ExecuteVote(flagSet *pflag.FlagSet) { } log.Debugf("Calling Vote() with arguments rogueData = %+v, account address = %s, backup node actions to ignore = %s", rogueData, account.Address, backupNodeActionsToIgnore) - if err := cmdUtils.Vote(rpcParameters, config, account, stakerId, commitParams, rogueData, backupNodeActionsToIgnore); err != nil { + if err := cmdUtils.Vote(rpcParameters, blockMonitor, config, account, stakerId, commitParams, rogueData, backupNodeActionsToIgnore); err != nil { log.Errorf("%v\n", err) osUtils.Exit(1) } @@ -133,7 +134,7 @@ func (*UtilsStruct) HandleExit() { } //This function handles all the states of voting -func (*UtilsStruct) Vote(rpcParameters rpc.RPCParameters, config types.Configurations, account types.Account, stakerId uint32, commitParams *types.CommitParams, rogueData types.Rogue, backupNodeActionsToIgnore []string) error { +func (*UtilsStruct) Vote(rpcParameters rpc.RPCParameters, blockMonitor *block.BlockMonitor, config types.Configurations, account types.Account, stakerId uint32, commitParams *types.CommitParams, rogueData types.Rogue, backupNodeActionsToIgnore []string) error { header, err := clientUtils.GetLatestBlockWithRetry(rpcParameters) utils.CheckError("Error in getting block: ", err) for { @@ -142,9 +143,9 @@ func (*UtilsStruct) Vote(rpcParameters rpc.RPCParameters, config types.Configura return nil default: log.Debugf("Vote: Header value: %d", header.Number) - latestHeader, err := clientUtils.GetLatestBlockWithRetry(rpcParameters) - if err != nil { - log.Error("Error in fetching block: ", err) + latestHeader := blockMonitor.GetLatestBlock() + if latestHeader == nil { + log.Error("Block monitor returned nil header") continue } log.Debugf("Vote: Latest header value: %d", latestHeader.Number) diff --git a/cmd/vote_test.go b/cmd/vote_test.go index 97ce970d..2476dd40 100644 --- a/cmd/vote_test.go +++ b/cmd/vote_test.go @@ -4,11 +4,13 @@ import ( "context" "encoding/hex" "errors" + Types "github.com/ethereum/go-ethereum/core/types" "math/big" "os" "path" "path/filepath" "razor/accounts" + "razor/block" "razor/cache" "razor/core/types" "razor/pkg/bindings" @@ -16,9 +18,6 @@ import ( "razor/utils" "reflect" "testing" - "time" - - Types "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" @@ -176,7 +175,7 @@ func TestExecuteVote(t *testing.T) { flagSetMock.On("GetStringSliceRogueMode", mock.AnythingOfType("*pflag.FlagSet")).Return(tt.args.rogueMode, tt.args.rogueModeErr) cmdUtilsMock.On("InitJobAndCollectionCache", mock.Anything).Return(&cache.JobsCache{}, &cache.CollectionsCache{}, big.NewInt(100), nil) cmdUtilsMock.On("HandleExit").Return() - cmdUtilsMock.On("Vote", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tt.args.voteErr) + cmdUtilsMock.On("Vote", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tt.args.voteErr) osMock.On("Exit", mock.AnythingOfType("int")).Return() utils := &UtilsStruct{} @@ -1338,12 +1337,9 @@ func TestVote(t *testing.T) { errChan := make(chan error) // Run Vote function in a goroutine go func() { - errChan <- ut.Vote(localRpcParameters, config, account, stakerId, commitParams, rogueData, backupNodeActionsToIgnore) + errChan <- ut.Vote(localRpcParameters, &block.BlockMonitor{}, config, account, stakerId, commitParams, rogueData, backupNodeActionsToIgnore) }() - // Wait for some time to allow Vote function to execute - time.Sleep(time.Second * 2) - // Cancel the context to simulate its done cancel() From 486a93adac39e932a6a54b7e42f442719c38b977 Mon Sep 17 00:00:00 2001 From: Yashk767 <76935991+Yashk767@users.noreply.github.com> Date: Fri, 28 Feb 2025 17:21:15 +0530 Subject: [PATCH 5/9] fix: added validation to check if index to fetch element is within limits (#1270) --- cmd/propose.go | 6 ++++++ cmd/propose_test.go | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/cmd/propose.go b/cmd/propose.go index 1f74baf8..03d5de70 100644 --- a/cmd/propose.go +++ b/cmd/propose.go @@ -113,6 +113,12 @@ func (*UtilsStruct) Propose(rpcParameters rpc.RPCParameters, config types.Config return err } log.Debug("Propose: Sorted proposed blocks: ", sortedProposedBlocks) + + if numOfProposedBlocks <= 0 || len(sortedProposedBlocks) < int(numOfProposedBlocks) { + log.Errorf("Invalid numOfProposedBlocks (%d) or mismatch with sortedProposedBlocks length (%d)", numOfProposedBlocks, len(sortedProposedBlocks)) + return errors.New("proposed blocks count mismatch") + } + lastBlockIndex := sortedProposedBlocks[numOfProposedBlocks-1] log.Debug("Propose: Last block index: ", lastBlockIndex) lastProposedBlockStruct, err := razorUtils.GetProposedBlock(rpcParameters, epoch, lastBlockIndex) diff --git a/cmd/propose_test.go b/cmd/propose_test.go index f7def015..c94c8419 100644 --- a/cmd/propose_test.go +++ b/cmd/propose_test.go @@ -497,6 +497,21 @@ func TestPropose(t *testing.T) { }, wantErr: errors.New("txnOpts error"), }, + { + name: "Test 20: When there is a mismatch in number of proposed blocks and length of sorted proposed blocks array", + args: args{ + state: 2, + staker: bindings.StructsStaker{}, + numStakers: 5, + biggestStake: big.NewInt(1).Mul(big.NewInt(5356), big.NewInt(1e18)), + biggestStakerId: 2, + salt: saltBytes32, + iteration: 1, + numOfProposedBlocks: 3, + sortedProposedBlockIds: []uint32{2, 1}, + }, + wantErr: errors.New("proposed blocks count mismatch"), + }, } for _, tt := range tests { SetUpMockInterfaces() From 4641fd82aa47d2de9c64f86a5fdac5ce00a1c0f2 Mon Sep 17 00:00:00 2001 From: Yashk767 <76935991+Yashk767@users.noreply.github.com> Date: Wed, 12 Mar 2025 21:16:36 +0530 Subject: [PATCH 6/9] fix: setconfig command fails on new vm for the first run of a staker (#1271) * hotfix: removed getConfigData() call from setConfig command * chore: update version to v2.1.0 * refactor: removed unwanted 'InitializeCommandDependencies()' from import and create command --- cmd/create.go | 6 ++++-- cmd/import.go | 6 ++++-- cmd/setConfig.go | 4 ++-- core/version.go | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/cmd/create.go b/cmd/create.go index 8e0bde8b..71ca08a9 100644 --- a/cmd/create.go +++ b/cmd/create.go @@ -28,8 +28,10 @@ func initialiseCreate(cmd *cobra.Command, args []string) { //This function sets the flags appropriately and executes the Create function func (*UtilsStruct) ExecuteCreate(flagSet *pflag.FlagSet) { - _, _, _, _, err := InitializeCommandDependencies(flagSet) - utils.CheckError("Error in initialising command dependencies: ", err) + config, err := cmdUtils.GetConfigData() + utils.CheckError("Error in getting config: ", err) + log.Debug("Checking to assign log file...") + fileUtils.AssignLogFile(flagSet, config) log.Info("The password should be of minimum 8 characters containing least 1 uppercase, lowercase, digit and special character.") password := razorUtils.AssignPassword(flagSet) log.Debug("ExecuteCreate: Calling Create() with argument as input password") diff --git a/cmd/import.go b/cmd/import.go index 4970b6dc..21865520 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -29,8 +29,10 @@ func initialiseImport(cmd *cobra.Command, args []string) { //This function sets the flags appropriately and executes the ImportAccount function func (*UtilsStruct) ExecuteImport(flagSet *pflag.FlagSet) { - _, _, _, _, err := InitializeCommandDependencies(flagSet) - utils.CheckError("Error in initialising command dependencies: ", err) + config, err := cmdUtils.GetConfigData() + utils.CheckError("Error in getting config: ", err) + log.Debug("Checking to assign log file...") + fileUtils.AssignLogFile(flagSet, config) log.Debug("Calling ImportAccount()...") account, err := cmdUtils.ImportAccount() utils.CheckError("Import error: ", err) diff --git a/cmd/setConfig.go b/cmd/setConfig.go index 1927b5ef..4008bbcd 100644 --- a/cmd/setConfig.go +++ b/cmd/setConfig.go @@ -29,8 +29,8 @@ Example: // This function returns the error if there is any and sets the config func (*UtilsStruct) SetConfig(flagSet *pflag.FlagSet) error { - _, _, _, _, err := InitializeCommandDependencies(flagSet) - utils.CheckError("Error in initialising command dependencies: ", err) + log.Debug("Checking to assign log file...") + fileUtils.AssignLogFile(flagSet, types.Configurations{}) flagDetails := []types.FlagDetail{ {Name: "provider", Type: "string"}, diff --git a/core/version.go b/core/version.go index 15a0e147..2c9cced4 100644 --- a/core/version.go +++ b/core/version.go @@ -4,7 +4,7 @@ import "fmt" const ( VersionMajor = 2 // Major version component of the current release - VersionMinor = 0 // Minor version component of the current release + VersionMinor = 1 // Minor version component of the current release VersionPatch = 0 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string ) From 33c6ce40b17c89448b0377c691de24199ce548aa Mon Sep 17 00:00:00 2001 From: Yashk767 <76935991+Yashk767@users.noreply.github.com> Date: Thu, 13 Mar 2025 14:13:17 +0530 Subject: [PATCH 7/9] ci: updated actions/cache from v2 to v4 (#1272) --- .github/workflows/develop.yml | 4 ++-- .github/workflows/release.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index 4ab39ca6..048e739c 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -24,7 +24,7 @@ jobs: with: go-version: 1.23 - name: Cache npm modules - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} @@ -32,7 +32,7 @@ jobs: ${{ runner.os }}-node- - name: Cache Go dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7736dece..99f3de09 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: with: go-version: 1.23 - name: Cache npm modules - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} @@ -29,7 +29,7 @@ jobs: ${{ runner.os }}-node- - name: Cache Go dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} From e0a41d9626d28aabb74a5116ed927d7485c3ca3f Mon Sep 17 00:00:00 2001 From: Yashk767 <76935991+Yashk767@users.noreply.github.com> Date: Thu, 20 Mar 2025 15:36:12 +0530 Subject: [PATCH 8/9] ci: update public RPC in tests to ensure CI runs successfully (#1274) --- utils/asset_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/utils/asset_test.go b/utils/asset_test.go index 65c25e19..13117881 100644 --- a/utils/asset_test.go +++ b/utils/asset_test.go @@ -598,16 +598,16 @@ func TestGetDataToCommitFromJobs(t *testing.T) { }, {Id: 6, SelectorType: 0, Weight: 100, Power: 6, Name: "ethusd_uniswapv2", Selector: "result", - Url: `{"type": "POST","url": "https://rpc.ankr.com/eth","body": {"jsonrpc":"2.0","id":7269270904970082,"method":"eth_call","params":[{"from":"0x0000000000000000000000000000000000000000","data":"0xd06ca61f0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000050de6856358cc35f3a9a57eaaa34bd4cb707d2cd0000000000000000000000008e870d67f660d95d5be530380d0ec0bd388289e1","to":"0x7a250d5630b4cf539739df2c5dacb4c659f2488d"},"latest"]},"header": {"content-type": "application/json"}, "returnType": "hexArray[1]"}`, + Url: `{"type": "POST","url": "https://ethereum-rpc.publicnode.com","body": {"jsonrpc":"2.0","id":7269270904970082,"method":"eth_call","params":[{"from":"0x0000000000000000000000000000000000000000","data":"0xd06ca61f0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000050de6856358cc35f3a9a57eaaa34bd4cb707d2cd0000000000000000000000008e870d67f660d95d5be530380d0ec0bd388289e1","to":"0x7a250d5630b4cf539739df2c5dacb4c659f2488d"},"latest"]},"header": {"content-type": "application/json"}, "returnType": "hexArray[1]"}`, }, {Id: 7, SelectorType: 0, Weight: 100, Power: 2, Name: "ethusd_uniswapv3", Selector: "result", - Url: `{"type": "POST","url": "https://rpc.ankr.com/eth","body": {"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0xb27308f9f90d607463bb33ea1bebb41c27ce5ab6","data":"0xf7729d43000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000bb80000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000"},"latest"],"id":5},"header": {"content-type": "application/json"}, "returnType": "hex"}`, + Url: `{"type": "POST","url": "https://ethereum-rpc.publicnode.com","body": {"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0xb27308f9f90d607463bb33ea1bebb41c27ce5ab6","data":"0xf7729d43000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000bb80000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000"},"latest"],"id":5},"header": {"content-type": "application/json"}, "returnType": "hex"}`, }, // This is a duplicate job to check if cache is working correctly for POST Jobs {Id: 8, SelectorType: 0, Weight: 100, Power: 2, Name: "ethusd_uniswapv3_duplicate", Selector: "result", - Url: `{"type": "POST","url": "https://rpc.ankr.com/eth","body": {"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0xb27308f9f90d607463bb33ea1bebb41c27ce5ab6","data":"0xf7729d43000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000bb80000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000"},"latest"],"id":5},"header": {"content-type": "application/json"}, "returnType": "hex"}`, + Url: `{"type": "POST","url": "https://ethereum-rpc.publicnode.com","body": {"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0xb27308f9f90d607463bb33ea1bebb41c27ce5ab6","data":"0xf7729d43000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000bb80000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000"},"latest"],"id":5},"header": {"content-type": "application/json"}, "returnType": "hex"}`, }, // This is a duplicate job to check if cache is working correctly for GET Jobs {Id: 9, SelectorType: 0, Weight: 10, @@ -686,12 +686,12 @@ func TestGetDataToCommitFromJob(t *testing.T) { postJobUniswapV3 := bindings.StructsJob{Id: 1, SelectorType: 0, Weight: 100, Power: 2, Name: "ethusd_sample", Selector: "result", - Url: `{"type": "POST","url": "https://rpc.ankr.com/eth","body": {"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0xb27308f9f90d607463bb33ea1bebb41c27ce5ab6","data":"0xf7729d43000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000bb80000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000"},"latest"],"id":5},"header": {"content-type": "application/json"}, "returnType": "hex"}`, + Url: `{"type": "POST","url": "https://ethereum-rpc.publicnode.com","body": {"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0xb27308f9f90d607463bb33ea1bebb41c27ce5ab6","data":"0xf7729d43000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000bb80000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000"},"latest"],"id":5},"header": {"content-type": "application/json"}, "returnType": "hex"}`, } postJobUniswapV2 := bindings.StructsJob{Id: 1, SelectorType: 0, Weight: 100, Power: 6, Name: "ethusd_sample", Selector: "result", - Url: `{"type": "POST","url": "https://rpc.ankr.com/eth","body": {"jsonrpc":"2.0","id":7269270904970082,"method":"eth_call","params":[{"from":"0x0000000000000000000000000000000000000000","data":"0xd06ca61f0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000050de6856358cc35f3a9a57eaaa34bd4cb707d2cd0000000000000000000000008e870d67f660d95d5be530380d0ec0bd388289e1","to":"0x7a250d5630b4cf539739df2c5dacb4c659f2488d"},"latest"]},"header": {"content-type": "application/json"}, "returnType": "hexArray[1]"}`, + Url: `{"type": "POST","url": "https://ethereum-rpc.publicnode.com","body": {"jsonrpc":"2.0","id":7269270904970082,"method":"eth_call","params":[{"from":"0x0000000000000000000000000000000000000000","data":"0xd06ca61f0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000050de6856358cc35f3a9a57eaaa34bd4cb707d2cd0000000000000000000000008e870d67f660d95d5be530380d0ec0bd388289e1","to":"0x7a250d5630b4cf539739df2c5dacb4c659f2488d"},"latest"]},"header": {"content-type": "application/json"}, "returnType": "hexArray[1]"}`, } arrayOfObjectsJob := bindings.StructsJob{Id: 1, SelectorType: 0, Weight: 100, From 1467c796095a5797345a234246a3a79852f98b04 Mon Sep 17 00:00:00 2001 From: Yashk767 <76935991+Yashk767@users.noreply.github.com> Date: Thu, 20 Mar 2025 18:35:13 +0530 Subject: [PATCH 9/9] chore: updated oracle node version to v2.1.1 (#1275) --- core/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/version.go b/core/version.go index 2c9cced4..5c2293b5 100644 --- a/core/version.go +++ b/core/version.go @@ -5,7 +5,7 @@ import "fmt" const ( VersionMajor = 2 // Major version component of the current release VersionMinor = 1 // Minor version component of the current release - VersionPatch = 0 // Patch version component of the current release + VersionPatch = 1 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string )