-
Notifications
You must be signed in to change notification settings - Fork 10
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
Cross-spork client checks for boundaries #263
Conversation
WalkthroughThe recent changes encompass improvements in error logging, refinement of client setup for cross-spork functionality, and enhancements to spork configuration robustness. These updates include detailed error logging enhancements, the introduction of a new Changes
Assessment against linked issues
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (invoked as PR comments)
Additionally, you can add CodeRabbit Configration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Review Details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files ignored due to path filters (4)
go.mod
is excluded by!**/*.mod
go.sum
is excluded by!**/*.sum
tests/go.mod
is excluded by!**/*.mod
tests/go.sum
is excluded by!**/*.sum
Files selected for processing (8)
- api/api.go (2 hunks)
- bootstrap/bootstrap.go (7 hunks)
- services/ingestion/engine.go (4 hunks)
- services/ingestion/subscriber_test.go (2 hunks)
- services/requester/cross-spork_client.go (5 hunks)
- services/requester/cross-spork_client_test.go (1 hunks)
- services/requester/requester.go (10 hunks)
- services/testutils/mock_client.go (1 hunks)
Files skipped from review due to trivial changes (1)
- api/api.go
Additional comments not posted (25)
services/ingestion/subscriber_test.go (3)
11-11
: Ensure the new importtestutils
is utilized effectively in the test setup.
26-27
: Refactoring to useSetupClientForRange
improves modularity and reusability of client setup.
29-29
: Good use ofSetupClientForRange
for setting up thecurrentClient
. This maintains consistency in client setup across tests.services/testutils/mock_client.go (3)
1-1
: Proper package declaration fortestutils
.
12-18
: Introduction ofMockClient
with functional fields allows flexible mocking of client behaviors, enhancing testability.
41-84
:SetupClientForRange
function is well-implemented, providing a convenient way to configure mock clients for specific block height ranges. This is crucial for testing different scenarios in a controlled environment.services/requester/cross-spork_client_test.go (4)
1-1
: Proper package declaration forrequester
.
15-31
: Comprehensive tests forsporkClient.contains
method. These tests ensure that the method accurately checks if a given height is within the client's range.
34-67
: Tests forsporkClients
adding and validation logic are thorough, ensuring that clients are added correctly and that their ranges are continuous.
70-126
: Extensive testing ofCrossSporkClient
functionality, covering scenarios from client retrieval based on height to error handling for out-of-range queries. These tests are crucial for ensuring the robustness of cross-spork client operations.services/requester/cross-spork_client.go (4)
5-5
: Importing necessary packages for error handling and logging.
15-26
: Definition ofsporkClient
struct andcontains
method. This setup is essential for determining if a height is within the spork's range, which is a core functionality of theCrossSporkClient
.
30-84
: Implementation ofsporkClients
methodsadd
andget
. These methods are well-designed to manage spork clients effectively, ensuring that they are added correctly and can be retrieved based on block height.
Line range hint
95-209
: TheCrossSporkClient
struct and its methods are implemented to handle different spork clients based on block height. This is crucial for the system's ability to handle requests across different sporks seamlessly.bootstrap/bootstrap.go (3)
60-81
: Integration ofCrossSporkClient
in the bootstrap process. This change is crucial for enabling the system to handle cross-spork capabilities right from the start.
Line range hint
125-155
: The changes tostartIngestion
to useCrossSporkClient
ensure that the ingestion process can handle data across different sporks. This is vital for the robustness and flexibility of the system.
Line range hint
191-209
: Updates tostartServer
to utilizeCrossSporkClient
. These changes are essential for ensuring that the server can handle requests across different sporks, enhancing the system's scalability and reliability.services/ingestion/engine.go (2)
128-128
: Enhanced logging inprocessEvents
provides better visibility into the ingestion process, which is crucial for monitoring and debugging.
179-189
: The detailed logging inindexBlock
improves traceability of block processing, which is essential for understanding the flow of data through the system.services/requester/requester.go (6)
91-98
: The update to use*CrossSporkClient
in theEVM
struct and its constructor aligns with the PR's objectives to handle cross-spork clients effectively.
165-165
: Enhanced error logging inSendRawTransaction
improves visibility and is beneficial for debugging transaction issues.
272-277
: Enhanced error logging inGetBalance
improves diagnostics and is crucial for troubleshooting issues in financial applications.
305-309
: Updated error logging inGetNonce
enhances operational monitoring and debugging capabilities.
343-348
: Updated error handling and logging inCall
enhance diagnostics and traceability, which are crucial for blockchain operations.
362-362
: Logging the result inCall
method is a good practice for traceability and debugging.
services/requester/requester.go
Outdated
go func(id flow.Identifier) { | ||
res, _ := e.client.GetTransactionResult(context.Background(), id) | ||
if res != nil && res.Error != nil { | ||
e.logger.Error(). | ||
Str("flow-id", id.String()). | ||
Str("events", fmt.Sprintf("%v", res.Events)). | ||
Msg("flow transaction executed successfully") | ||
}(flowTx.ID()) | ||
} | ||
Err(res.Error). | ||
Msg("flow transaction failed to execute") | ||
return | ||
} | ||
|
||
e.logger.Info(). | ||
Str("flow-id", id.String()). | ||
Str("events", fmt.Sprintf("%v", res.Events)). | ||
Str("status", res.Status.String()). | ||
Msg("flow transaction executed successfully") | ||
}(flowTx.ID()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Asynchronous logging of transaction results in signAndSend
is a good practice for non-blocking operations. However, consider adding nil checks before dereferencing res
to avoid potential runtime panics.
if res != nil {
if res.Error != nil {
e.logger.Error().Str("flow-id", id.String()).Err(res.Error).Msg("flow transaction failed to execute")
} else {
e.logger.Info().Str("flow-id", id.String()).Str("events", fmt.Sprintf("%v", res.Events)).Str("status", res.Status.String()).Msg("flow transaction executed successfully")
}
}
"github.com/rs/zerolog" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
type mockClient struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved
@@ -0,0 +1,84 @@ | |||
package testutils |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved to here
services/requester/requester.go
Outdated
|
||
e.logger.Debug(). | ||
go func(id flow.Identifier) { | ||
res, _ := e.client.GetTransactionResult(context.Background(), id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: fetching the tx result immediately doesn't tell you if the tx actually executed successfully. it will always return return pending
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed for #264
this change doesn't really belong in this PR
// make sure each last height is one smaller than next range first height | ||
for i := 0; i < len(lasts)-1; i++ { | ||
if lasts[i]+1 != firsts[i+1] { | ||
return false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it'd be helpful to log which blocks were missing between which clients
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how would you report that? I guess changing this to return an error? but then what is the method? mustBeContinuius
feels weird?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe checkContinuous
?
This is fine, it will just be a bit of manual checking for the operator if the list is not contiguous
firsts := make([]uint64, len(*s)) | ||
lasts := make([]uint64, len(*s)) | ||
|
||
for i, c := range *s { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think you could simplify this logic by sorting the list of clients first, then iterating over the list once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
Outside diff range and nitpick comments (4)
tests/web3js/eth_logs_filtering_test.js (1)
Line range hint
57-57
: Use strict equality===
for comparisons to avoid type coercion issues.- .filter(v => v.A == repeatA) + .filter(v => v.A === repeatA)tests/web3js/eth_streaming_test.js (1)
Line range hint
31-43
: Avoid usingasync
functions as Promise executors to prevent potential issues with unhandled promise rejections.- let doneBlocks = new Promise(async (res, rej) => { + let doneBlocks = new Promise((res, rej) => { - let doneTxs = new Promise(async (res, rej) => { + let doneTxs = new Promise((res, rej) => { - let doneAddressLogs = new Promise(async (res, rej) => { + let doneAddressLogs = new Promise((res, rej) => {Also applies to: 48-58, 63-75
tests/web3js/eth_streaming_filters_test.js (2)
Line range hint
10-10
: Replacelet
withconst
for variables that are assigned only once to ensure immutability where possible.- let contractDeployment = await helpers.deployContract("storage") + const contractDeployment = await helpers.deployContract("storage") - let contractAddress = contractDeployment.receipt.contractAddress + const contractAddress = contractDeployment.receipt.contractAddress - let contractDeployment2 = await helpers.deployContract("storage") + const contractDeployment2 = await helpers.deployContract("storage") - let contractAddress2 = contractDeployment2.receipt.contractAddress + const contractAddress2 = contractDeployment2.receipt.contractAddress - let repeatA = 10 + const repeatA = 10 - let ws = new Web3("ws://127.0.0.1:8545") + const ws = new Web3("ws://127.0.0.1:8545") - let storageContract = new ws.eth.Contract(storageABI, contractAddress) + const storageContract = new ws.eth.Contract(storageABI, contractAddress) - let storageContract2 = new ws.eth.Contract(storageABI, contractAddress) + const storageContract2 = new ws.eth.Contract(storageABI, contractAddress) - let calculatedEvent = storageContract.events.Calculated + const calculatedEvent = storageContract.events.Calculated - let rawSubscribe = filter => ws.eth.subscribe('logs', filter) + const rawSubscribe = filter => ws.eth.subscribe('logs', filter)Also applies to: 35-35, 40-40, 42-42, 48-48, 70-70, 71-71, 74-74, 75-75, 77-77, 86-86, 88-88, 89-89, 90-90, 92-92, 97-97, 153-153, 164-164
Line range hint
38-38
: Use strict inequality!==
for comparisons to avoid type coercion issues.- if (allLogs[i].returnValues != undefined) { + if (allLogs[i].returnValues !== undefined) {
Review Details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files ignored due to path filters (2)
tests/go.mod
is excluded by!**/*.mod
tests/go.sum
is excluded by!**/*.sum
Files selected for processing (6)
- services/requester/cross-spork_client.go (5 hunks)
- services/requester/cross-spork_client_test.go (1 hunks)
- services/requester/requester.go (10 hunks)
- tests/web3js/eth_logs_filtering_test.js (2 hunks)
- tests/web3js/eth_streaming_filters_test.js (1 hunks)
- tests/web3js/eth_streaming_test.js (1 hunks)
Files skipped from review as they are similar to previous changes (2)
- services/requester/cross-spork_client_test.go
- services/requester/requester.go
Additional Context Used
Biome (45)
tests/web3js/eth_logs_filtering_test.js (8)
57-57: Use === instead of ==.
== is only allowed when comparing againstnull
9-9: This let declares a variable that is only assigned once.
10-10: This let declares a variable that is only assigned once.
12-12: This let declares a variable that is only assigned once.
22-22: This let declares a variable that is only assigned once.
31-31: This let declares a variable that is only assigned once.
45-45: This let declares a variable that is only assigned once.
59-59: This let declares a variable that is only assigned once.
tests/web3js/eth_streaming_filters_test.js (19)
38-38: Use !== instead of !=.
!= is only allowed when comparing againstnull
10-10: This let declares a variable that is only assigned once.
35-35: This let declares a variable that is only assigned once.
40-40: This let declares a variable that is only assigned once.
42-42: This let declares a variable that is only assigned once.
48-48: This let declares a variable that is only assigned once.
70-70: This let declares a variable that is only assigned once.
71-71: This let declares a variable that is only assigned once.
74-74: This let declares a variable that is only assigned once.
75-75: This let declares a variable that is only assigned once.
77-77: This let declares a variable that is only assigned once.
86-86: This let declares a variable that is only assigned once.
88-88: This let declares a variable that is only assigned once.
89-89: This let declares a variable that is only assigned once.
90-90: This let declares a variable that is only assigned once.
92-92: This let declares a variable that is only assigned once.
97-97: This let declares a variable that is only assigned once.
153-153: This let declares a variable that is only assigned once.
164-164: This let declares a variable that is only assigned once.
tests/web3js/eth_streaming_test.js (18)
31-43: Promise executor functions should not be
async
.
48-58: Promise executor functions should not be
async
.
63-75: Promise executor functions should not be
async
.
11-11: This let declares a variable that is only assigned once.
12-12: This let declares a variable that is only assigned once.
14-14: This let declares a variable that is only assigned once.
23-23: This let declares a variable that is only assigned once.
30-30: This let declares a variable that is only assigned once.
31-31: This let declares a variable that is only assigned once.
32-32: This let declares a variable that is only assigned once.
47-47: This let declares a variable that is only assigned once.
48-48: This let declares a variable that is only assigned once.
49-49: This let declares a variable that is only assigned once.
61-61: This let declares a variable that is only assigned once.
63-63: This let declares a variable that is only assigned once.
64-64: This let declares a variable that is only assigned once.
80-80: This let declares a variable that is only assigned once.
83-83: This let declares a variable that is only assigned once.
@@ -4,6 +4,8 @@ const helpers = require('./helpers') | |||
const web3 = conf.web3 | |||
|
|||
it('emit logs and retrieve them using different filters', async() => { | |||
setTimeout(() => process.exit(1), 19*1000) // hack if the ws connection is not closed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using Mocha's built-in timeout mechanism instead of a manual setTimeout
for test timeouts.
@@ -4,6 +4,8 @@ | |||
const web3 = conf.web3 | |||
|
|||
it('emit logs and retrieve them using different filters', async() => { | |||
setTimeout(() => process.exit(1), 19*1000) // hack if the ws connection is not closed | |||
|
|||
let deployed = await helpers.deployContract("storage") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace let
with const
for variables that are assigned only once to ensure immutability where possible.
- let deployed = await helpers.deployContract("storage")
+ const deployed = await helpers.deployContract("storage")
- let contractAddress = deployed.receipt.contractAddress
+ const contractAddress = deployed.receipt.contractAddress
- let repeatA = 10
+ const repeatA = 10
- let latest = await web3.eth.getBlockNumber()
+ const latest = await web3.eth.getBlockNumber()
- let events = await deployed.contract.getPastEvents('Calculated', {
+ const events = await deployed.contract.getPastEvents('Calculated', {
Also applies to: 10-10, 12-12, 22-22, 31-31, 45-45, 59-59
Committable suggestion was skipped due low confidence.
@@ -6,6 +6,8 @@ const {Web3} = require("web3"); | |||
const timeout = 30 // test timeout seconds | |||
|
|||
it('streaming of logs using filters', async() => { | |||
setTimeout(() => process.exit(1), (timeout-1)*1000) // hack if the ws connection is not closed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using Mocha's built-in timeout mechanism instead of a manual setTimeout
for test timeouts.
@@ -6,6 +6,8 @@ | |||
const timeout = 30 // test timeout seconds | |||
|
|||
it('streaming of logs using filters', async() => { | |||
setTimeout(() => process.exit(1), (timeout-1)*1000) // hack if the ws connection is not closed | |||
|
|||
let deployed = await helpers.deployContract("storage") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace let
with const
for variables that are assigned only once to ensure immutability where possible.
- let deployed = await helpers.deployContract("storage")
+ const deployed = await helpers.deployContract("storage")
- let contractAddress = deployed.receipt.contractAddress
+ const contractAddress = deployed.receipt.contractAddress
- let repeatA = 10
+ const repeatA = 10
- let ws = new Web3("ws://127.0.0.1:8545")
+ const ws = new Web3("ws://127.0.0.1:8545")
- let blockCount = 0
+ const blockCount = 0
- let blockHashes = []
+ const blockHashes = []
- let doneBlocks = new Promise(async (res, rej) => {
+ const doneBlocks = new Promise((res, rej) => {
Also applies to: 12-12, 14-14, 23-23, 30-30, 31-31, 32-32, 47-47, 48-48, 49-49, 61-61, 63-63, 64-64, 80-80, 83-83
Committable suggestion was skipped due low confidence.
var ErrOutOfRange = errors.New("height is out of range for provided spork clients") | ||
|
||
type sporkClient struct { | ||
firstHeight uint64 | ||
lastHeight uint64 | ||
client access.Client | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implementation of CrossSporkClient
is robust with appropriate error handling and continuity checks. Consider enhancing the error messages and logs for better traceability.
- return fmt.Errorf("could not get latest height using the spork client: %w", err)
+ return fmt.Errorf("error retrieving latest block header from spork client: %w", err)
- return fmt.Errorf("could not get node info using the spork client: %w", err)
+ return fmt.Errorf("error retrieving node version info from spork client: %w", err)
- c.logger.Debug().Msg("using previous spork client")
+ c.logger.Debug().Str("client", client.ID()).Msg("selected spork client based on height")
Also applies to: 23-26, 28-54, 56-65, 67-77, 88-122, 130-202
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.
var ErrOutOfRange = errors.New("height is out of range for provided spork clients") | |
type sporkClient struct { | |
firstHeight uint64 | |
lastHeight uint64 | |
client access.Client | |
} | |
var ErrOutOfRange = errors.New("height is out of range for provided spork clients") | |
type sporkClient struct { | |
firstHeight uint64 | |
lastHeight uint64 | |
client access.Client | |
} | |
func (c *CrossSporkClient) someFunction() error { | |
// Example function to show the application of the diff | |
if err != nil { | |
return fmt.Errorf("error retrieving latest block header from spork client: %w", err) | |
} | |
if err != nil { | |
return fmt.Errorf("error retrieving node version info from spork client: %w", err) | |
} | |
c.logger.Debug().Str("client", client.ID()).Msg("selected spork client based on height") | |
return nil | |
} |
@@ -65,6 +65,8 @@ async function assertFilterLogs(subscription, expectedLogs) { | |||
} | |||
|
|||
it('streaming of logs using filters', async() => { | |||
setTimeout(() => process.exit(1), (timeout-1)*1000) // hack if the ws connection is not closed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using Mocha's built-in timeout mechanism instead of a manual setTimeout
for test timeouts.
Closes: #231
Description
This PR improves how cross-spork clients are handled. It adds a range for each client defined by first and last height in that spork, which enables more safety, first it enabled for all the clients to be checked if they create a continuous range of heights (without missing heights), secondly and more importantly, the requests error out if the height requested is out of range, which drops requests made to the AN and thus lower traffic and load.
Implementing this is important because there was a lot of requests for heights out of range being forwarded to ANs.
For contributor use:
master
branchFiles changed
in the Github PR explorerSummary by CodeRabbit
New Features
Improvements
Testing