-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(net): test syncing from geth #623
Conversation
7d253d2
to
053b091
Compare
053b091
to
d56aff0
Compare
@Rjected gm - planned next steps here? |
gm @gakonst still debugging an invalid sender error, looking through geth to see if I activated EIP155 correctly Then:
|
Cool - pls ping me if you're still blocked on this by eod (if you're online today?) so that we debug together as it's important we get confidence that it's the network and not us causing the peering issues |
920587b
to
76cb0f7
Compare
Codecov Report
📣 This organization is not using Codecov’s GitHub App Integration. We recommend you install it so Codecov can continue to function properly for your repositories. Learn more @@ Coverage Diff @@
## main #623 +/- ##
==========================================
+ Coverage 74.46% 75.35% +0.89%
==========================================
Files 319 321 +2
Lines 34844 34949 +105
==========================================
+ Hits 25945 26336 +391
+ Misses 8899 8613 -286
Flags with carried forward coverage won't be shown. Click here to find out more.
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it 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.
this looks great!
incredibly useful.
should we go over this after the call Monday to assess what's missing/blockers etc?
yeah that would be very useful, lets do it @mattsse |
c97b65a
to
2db2cc8
Compare
big refactor:
|
almost done, just noting down things left TODO:
We should have enough support code once this is done s.t. we can write all sorts of tests with geth, for example testing that reth passes the geth |
2b0e05d
to
659c95a
Compare
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 like where this landed. A big nitpick but I think we need some refactors and splitting in smaller PRs because it's a lot. I also feel we don't need dedicated crates for these and should be able to roll most in the existing ones?
5892531
to
368ba7d
Compare
887475f
to
82601c8
Compare
squashed the commits and rebased on main - this now only contains code related to The only thing blocking this PR is a |
77e2a39
to
afe1e75
Compare
* the tests properly sync
* introduce an extension trait to simplify the use of providers in sync tests * add test-utils feature in staged-sync
15b2810
to
ebada9a
Compare
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.
After tons of ether PRs and debugging, this will be very useful.
great work!
only smol nit.
and we need to discuss where to put this exactly.
crates/staged-sync/tests/sync.rs
Outdated
fs::remove_dir_all(dir_path).await.unwrap(); | ||
}) | ||
.await | ||
.unwrap(); |
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 believe this should be unnecessary because tempdir already does this on drop
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.
ah I had to do this because I was using into_path
, which requires manual deletion, but switching to path
works and does not require doing this
crates/staged-sync/tests/sync.rs
Outdated
fs::remove_dir_all(dir_path).await.unwrap(); | ||
}) | ||
.await | ||
.unwrap(); |
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.
same
tokio::spawn(async move { | ||
loop { | ||
if let (Ok(line), _line_str) = { | ||
let mut buf = String::new(); | ||
(err_reader.read_line(&mut buf), buf.clone()) | ||
} { | ||
if line == 0 { | ||
break | ||
} | ||
} | ||
} |
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 is just for debugging, right?
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.
print_logs
is for debugging, but prevent_blocking
is necessary to prevent the stderr pipe buffer from filling up and causing the test to hang. Using Drop
doesn't seem to work here because it causes geth to crash (probably due to EPIPE
, but I'm not entirely sure). I'm not sure if there's a better way to prevent the stderr pipe buffer from filling though
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.
can't we send to /dev/null instead and not bother with this? either way let's do in a followup
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 can't do it by default because Geth
captures the stderr to make sure rpc, p2p, etc are up when spawn
is called. So have to first pipe the Command
's output with Stdio::piped()
. Maybe we could spawn cat
or something, with geth's stderr as cat
's stdin
, and pipe cat to /dev/null
|
||
#[cfg(any(test, feature = "test-utils"))] | ||
/// Common helpers for integration testing. | ||
pub mod test_utils; |
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 wonder if staged-sync is the right crate here, I guess so we can use the pipeline and test certain parts of it against a GethInstance?
perhaps it would be appropriate to move to its own crate?
wdyt @onbjerg ?
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.
prefer it here, or in any node
-named packages (ref #1079 )
tokio::spawn(async move { | ||
loop { | ||
if let (Ok(line), _line_str) = { | ||
let mut buf = String::new(); | ||
(err_reader.read_line(&mut buf), buf.clone()) | ||
} { | ||
if line == 0 { | ||
break | ||
} | ||
} | ||
} |
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.
can't we send to /dev/null instead and not bother with this? either way let's do in a followup
|
||
#[cfg(any(test, feature = "test-utils"))] | ||
/// Common helpers for integration testing. | ||
pub mod test_utils; |
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.
prefer it here, or in any node
-named packages (ref #1079 )
crates/staged-sync/tests/sync.rs
Outdated
let remote_genesis = SealedHeader::from(provider.remote_genesis_block().await.unwrap()); | ||
|
||
let mut local_genesis_header: Header = chainspec.genesis().clone().into(); |
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.
Doesn't clique.0.genesis()
load Geth's genesis file? how is remote_genesis_block()
relevant here?
crates/staged-sync/tests/sync.rs
Outdated
let local_genesis = local_genesis_header.seal(); | ||
assert_eq!(local_genesis, remote_genesis, "genesis blocks should match, we computed {local_genesis:#?} but geth computed {remote_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.
this is a redundant sanity check right? aren't these always going to be the same since they're both from geth?
crates/staged-sync/tests/sync.rs
Outdated
reth_tracing::init_test_tracing(); | ||
tokio::time::timeout(GETH_TIMEOUT, async move { | ||
// first create a signer that we will fund so we can make transactions | ||
let chain_id = 13337u64; | ||
let data_dir = tempfile::tempdir().expect("should be able to create temp geth datadir"); | ||
let dir_path = data_dir.path(); | ||
tracing::info!( | ||
data_dir=?dir_path, | ||
"initializing geth instance" | ||
); | ||
|
||
// this creates a funded geth | ||
let clique_geth = Geth::new() | ||
.chain_id(chain_id) | ||
.p2p_port(unused_port()) | ||
.data_dir(dir_path.to_str().unwrap()); | ||
|
||
// build the funded geth | ||
let (mut clique, provider) = CliqueGethInstance::new(clique_geth, None).await; | ||
let geth_p2p_port = clique.0.p2p_port().expect("geth should be configured with a p2p port"); | ||
tracing::info!( | ||
p2p_port=%geth_p2p_port, | ||
rpc_port=%clique.0.port(), | ||
"configured clique geth instance in keepalive test" | ||
); | ||
|
||
// don't print logs, but drain the stderr | ||
clique.prevent_blocking().await; | ||
|
||
// get geth to start producing blocks - use a blank password | ||
let clique_private_key = clique.0.clique_private_key().clone().expect("clique should be configured with a private key"); | ||
provider.enable_mining(clique_private_key, "".into()).await.unwrap(); | ||
|
||
// === check that we have the same genesis hash === | ||
|
||
// get the chainspec from the genesis we configured for geth | ||
let mut chainspec: ChainSpec = clique.0.genesis().clone().expect("clique should be configured with a genesis").into(); | ||
let remote_genesis = SealedHeader::from(provider.remote_genesis_block().await.unwrap()); | ||
|
||
let mut local_genesis_header = Header::from(chainspec.genesis().clone()); | ||
|
||
let hardforks = chainspec.hardforks(); | ||
|
||
// set initial base fee depending on eip-1559 | ||
if let Some(0) = hardforks.get(&Hardfork::London) { | ||
local_genesis_header.base_fee_per_gas = Some(EIP1559_INITIAL_BASE_FEE); | ||
} | ||
|
||
let local_genesis = local_genesis_header.seal(); | ||
assert_eq!(local_genesis, remote_genesis, "genesis blocks should match, we computed {local_genesis:#?} but geth computed {remote_genesis:#?}"); | ||
|
||
// set the chainspec genesis hash | ||
chainspec.genesis_hash = local_genesis.hash(); | ||
|
||
// === create many blocks === | ||
|
||
let nonces = 0..1000u64; | ||
let txs = nonces | ||
.map(|nonce| { | ||
// create a tx that just sends to the zero addr | ||
TypedTransaction::Eip1559(Eip1559TransactionRequest::new() | ||
.to(H160::zero()) | ||
.value(1u64) | ||
.nonce(nonce)) | ||
}); | ||
tracing::info!("generated transactions for blocks"); | ||
|
||
// finally send the txs to geth | ||
provider.send_requests(txs).await.unwrap(); | ||
|
||
let block = provider.get_block_number().await.unwrap(); | ||
assert!(block > U64::zero()); |
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 boilerplate should go to a helper function, since it's duped with the code above
crates/staged-sync/tests/sync.rs
Outdated
// wait for the session to be established | ||
let _peer_id = events.peer_added_and_established().await.unwrap(); |
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.
shouldn't we add a assert_eq!(geth_peer_id, peer_id)
here? what is the purpose of the keepalive stuff below?
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.
finally :) this exposed a lot of things to improve, so im glad we did this.
Co-authored-by: Georgios Konstantopoulos <[email protected]>
reth integration tests
This adds tests which spawn an instance of
geth
and configure it to produce blocks with cilque. Geth is sent transactions, which gets used to produce blocks. This is then used to test the following situations:Depends on:
TODO:
Genesis