-
Notifications
You must be signed in to change notification settings - Fork 7
In-process tests, optional dockerized validation node #132
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
base: main
Are you sure you want to change the base?
Conversation
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.
Pull Request Overview
This PR refactors the in-test infrastructure to use a new in-process LocalInstance
and ChainDriver
, replaces the previous TestHarness
and related service modules, extends the test framework with utilities and transaction-pool observers, and updates dependencies and CI settings for test support.
- Introduce
LocalInstance
andChainDriver
APIs and remove the oldTestHarness
/service modules - Update all vanilla and flashblocks tests to use the new driver-based interface
- Add
framework/utils.rs
, transaction-pool observation, test logging init, and new Cargo features for testing
Reviewed Changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated no comments.
Show a summary per file
File | Description |
---|---|
crates/op-rbuilder/src/tests/vanilla/ordering.rs | Switched from TestHarnessBuilder to LocalInstance & ChainDriver |
crates/op-rbuilder/src/tests/vanilla/data_availability.rs | Updated size-limit tests to use new driver API |
crates/op-rbuilder/src/tests/framework/utils.rs | Added testing helper traits (ChainDriverExt , BlockTransactionsExt , etc.) |
crates/op-rbuilder/src/tests/framework/instance.rs | Added LocalInstance implementation |
crates/op-rbuilder/Cargo.toml | Added testing dependencies & features (duplicate entries) |
.github/workflows/checks.yaml | Inject TESTS_TEMP_DIR env var for tests |
Comments suppressed due to low confidence (6)
crates/op-rbuilder/Cargo.toml:119
- There are duplicate
dashmap
entries in thisCargo.toml
(once as optional, once unqualified). Remove or consolidate one declaration to avoid cargo manifest parsing errors.
dashmap = { version = "6.1", optional = true }
crates/op-rbuilder/Cargo.toml:120
- Duplicate
nanoid
declaration—listed both as optional and non-optional further down. Consolidate these entries to avoid conflicts.
nanoid = { version = "0.4", optional = true }
crates/op-rbuilder/Cargo.toml:121
- You have two
reth-ipc
definitions (optional and non-optional). Remove the redundant entry to prevent cargo errors.
reth-ipc = { workspace = true, optional = true }
crates/op-rbuilder/Cargo.toml:122
- Duplicate
bollard
entries exist. Consolidate to a single declaration to keep the manifest valid.
bollard = { version = "0.19", optional = true }
crates/op-rbuilder/Cargo.toml:123
- [nitpick] The
tar
crate is only declared once, but please verify if it should also be gated under thetesting
feature rather than listed unconditionally.
tar = { version = "0.4", optional = true }
.github/workflows/checks.yaml:76
- The
TESTS_TEMP_DIR
environment variable is set here but not referenced in the test code. Either remove it or update the test framework to honor this variable.
TESTS_TEMP_DIR: ${{ github.workspace }}
Will follow up with another PR after this goes through for #133 |
} else { | ||
println!("{}", serde_json::to_string_pretty(&genesis)?); | ||
debug!("{}", serde_json::to_string_pretty(&genesis)?); |
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.
i think we want println here so we could easily copy genesis
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.
As part of this PR I have added support for printing all reth and op-rbuilder logs into console during tests. You can do this:
$ TEST_TRACE=on cargo test
$ TEST_TRACE=error cargo test
$ TEST_TRACE=info cargo test
$ TEST_TRACE=debug cargo test
$ TEST_TRACE=trace cargo test
And it will print out to console everything that happens during the test you need to debug at the debug level you need.
.duration_since(std::time::UNIX_EPOCH) | ||
.map_err(|_| eyre::eyre!("Failed to get current system time"))?; | ||
|
||
// block timestamp will be the max of the actual timestamp and the latest block |
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.
Were we using this logic anywhere before? Is there a need for this logic instead of spec-compliant logic?
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.
We are calling build_new_block
at various intervals but the chain supports 1s time resolution. This is here to ensure that if we build blocks in close enough intervals, that the assumed invariants still hold. Open to discussion whether we want to keep this logic or remove it.
.with_da_config(da_config) | ||
.build(); | ||
|
||
let node_builder = NodeBuilder::<_, OpChainSpec>::new(config.clone()) |
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.
Would we need to keep this in sync with the main?
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.
I will do that in a follow-up PR. The logic is slightly different between main
and LocalInstance
but I agree that the common bits need to be kept in sync in one place.
} | ||
} | ||
|
||
impl Drop for ExternalNode { |
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.
Big point to check:
i'm not sure that Drop is invoked when you ctrl + c from cargo test
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.
Added a handler that will clean up the test on ctrl-c.
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.
That is great!
I was struggling sometime with left op-reth instances, thanks a lot!
.raw_request::<(i32, i32), bool>("miner_setMaxDASize".into(), (0, 1)) | ||
.await?; | ||
assert!(call, "miner_setMaxDASize should be executed successfully"); | ||
|
||
let unfit_tx = harness.send_valid_transaction().await?; | ||
let block = generator.generate_block().await?; | ||
let unfit_tx = driver |
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.
loved it when we needed to just call send_valid_transaction and it was doing everything under the hood
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.
Added a helper method that does it.
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.
now this tests is:
#[tokio::test]
async fn block_size_limit() -> eyre::Result<()> {
let rbuilder = LocalInstance::standard().await?;
let driver = rbuilder.driver().await?;
// Set block da size to be small, so it won't include tx
let call = driver
.provider()
.raw_request::<(i32, i32), bool>("miner_setMaxDASize".into(), (0, 1))
.await?;
assert!(call, "miner_setMaxDASize should be executed successfully");
let (unfit_tx, block) = driver.build_new_block_with_valid_transaction().await?;
// tx should not be included because we set the tx_size_limit to 1
assert!(
!block.includes(&unfit_tx),
"transaction should not be included in the block"
);
Ok(())
}
.await?; | ||
let block = driver.build_new_block().await?; | ||
|
||
assert!(block |
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.
Why have we removed includes? :(
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 was not removed just not used in this test. Updated the test to use:
assert!(block.includes(valid_tx.tx_hash()));
assert!(block.includes(reverting_tx.tx_hash()));
"Pending pool must contain at max 50 txs {:?}", | ||
pool | ||
rbuilder.pool().pending_count() |
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.
also want to see queue count in here
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.
you can already do that, in txs.rs
you have:
pub fn count(&self, status: TransactionEvent) -> usize {
self.observations
.iter()
.filter(|tx| tx.value().back() == Some(&status))
.count()
}
pub fn pending_count(&self) -> usize {
self.count(TransactionEvent::Pending)
}
pub fn queued_count(&self) -> usize {
self.count(TransactionEvent::Queued)
}
pub fn dropped_count(&self) -> usize {
self.count(TransactionEvent::Discarded)
}
|
||
// Ensure that 10 extra txs got included | ||
assert!(block.includes_vec(txs)); | ||
assert!(txs.into_iter().all(|tx| block.includes(&tx))); |
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.
QOL decrease
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.
Now includes
supports individual txs and collections of txs.
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.
This snippet is now:
// Ensure that 10 extra txs got included
assert!(block.includes(&txs));
📝 Summary
This PR closes the following issues:
ExternalNode
#133Few things happened here:
RBuilder running in-process
Now we have a new type called
LocalInstance
that runs an entire RBuilder instance in-process. It uses IPC transport instead of HTTP for RPC and EngineAPI. ThisLocalInstance
representsop-rbuilder
node and can be configured by giving it an optionalNodeConfig
orRBuilderArgs
structures. Examples:Built-in validation node management
An external
op-reth
node can be attached to any test using the following snippet:When an external node is attached to a chain driver, it will automatically sync with the
LocalInstance
that is running and then ingest every newly built block. Only if the external node validates and accepts a block as its canonical chain the block building process is considered successful.We support attaching multiple validation node to one local instance:
Better
OpRbuilderArgs
defaultsThe
Default
implementation of the cli arguments type and all its descendants will use the defaults specified by clap attributes instead of rust default values.Chain Driver
When interacting with a
LocalInstance
we have nowChainDriver
that is used to trigger production of new blocks, get latest blocks, etc. It can be either instantiated byChainDriver::new(&local_instance)
orlocal_instance.driver()
.Better transaction pool events inspector
In
LocalInstance
all transaction pool events are recorded in a strongly typed manner insideTransactionPoolObserver
. We record their entire state history, so we can later validate the correct order of transitions. The public API for this is:Transactions have states that are instance of
TransactionEvent
from thetransaction-pool
crate in reth. Namely:Test tracing
You can now see detailed logs of your unit tests by setting the
TEST_TRACE
env variable. That will print out all reth and op-rbuilder logs to console when they're running. Usage:✅ I have completed the following steps:
make lint
make test