Compare commits

..

6 Commits

Author SHA1 Message Date
Omar Abdulla 8d4b461032 Fix formtting and clippy 2025-07-14 12:27:19 +03:00
Omar Abdulla d6365f173b Merge remote-tracking branch 'origin/main' into bugfix/transaction-indexing 2025-07-14 12:18:15 +03:00
Omar 772bd217c3 Fixing the CI on Ubuntu (#31)
* pin the version of geth used in CI

* pin the version of geth used in CI

* temp: run on each push

* pin the version of geth used in CI

* Make geth installation arch dependent

* Remove temp run on push to branch

* Add a comment on the need for pre-built binaries
2025-07-14 09:17:13 +00:00
Omar Abdulla 81b3d631a5 Introduce a custom kitchensink network 2025-07-11 11:26:08 +03:00
Omar Abdulla e9a9ee02c9 Small fix to logging consistency 2025-07-10 17:07:51 +03:00
Omar Abdulla 951f189af2 Retry getting transaction receipt 2025-07-10 16:48:02 +03:00
6 changed files with 107 additions and 52 deletions
+21 -2
View File
@@ -99,9 +99,28 @@ jobs:
- name: Install Geth on Ubuntu
if: matrix.os == 'ubuntu-24.04'
run: |
sudo add-apt-repository -y ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install -y ethereum protobuf-compiler
sudo apt-get install -y protobuf-compiler
# We were facing some issues in CI with the 1.16.* versions of geth, and specifically on
# Ubuntu. Eventually, we found out that the last version of geth that worked in our CI was
# version 1.15.11. Thus, this is the version that we want to use in CI. The PPA sadly does
# not have historic versions of Geth and therefore we need to resort to downloading pre
# built binaries for Geth and the surrounding tools which is what the following parts of
# the script do.
sudo apt-get install -y wget ca-certificates tar
ARCH=$(uname -m)
if [ "$ARCH" = "x86_64" ]; then
URL="https://gethstore.blob.core.windows.net/builds/geth-alltools-linux-amd64-1.15.11-36b2371c.tar.gz"
elif [ "$ARCH" = "aarch64" ]; then
URL="https://gethstore.blob.core.windows.net/builds/geth-alltools-linux-arm64-1.15.11-36b2371c.tar.gz"
else
echo "Unsupported architecture: $ARCH"
exit 1
fi
wget -qO- "$URL" | sudo tar xz -C /usr/local/bin --strip-components=1
geth --version
- name: Install Geth on macOS
if: matrix.os == 'macos-14'
Generated
+6 -6
View File
@@ -67,9 +67,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "alloy"
version = "1.0.9"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0093d23bf026b580c1f66ed3a053d8209c104a446c5264d3ad99587f6edef24e"
checksum = "ae58d888221eecf621595e2096836ce7cfc37be06bfa39d7f64aa6a3ea4c9e5b"
dependencies = [
"alloy-consensus",
"alloy-contract",
@@ -162,9 +162,9 @@ dependencies = [
[[package]]
name = "alloy-core"
version = "1.1.2"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3c5a28f166629752f2e7246b813cdea3243cca59aab2d4264b1fd68392c10eb"
checksum = "ad31216895d27d307369daa1393f5850b50bbbd372478a9fa951c095c210627e"
dependencies = [
"alloy-dyn-abi",
"alloy-json-abi",
@@ -175,9 +175,9 @@ dependencies = [
[[package]]
name = "alloy-dyn-abi"
version = "1.1.2"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18cc14d832bc3331ca22a1c7819de1ede99f58f61a7d123952af7dde8de124a6"
checksum = "7b95b3deca680efc7e9cba781f1a1db352fa1ea50e6384a514944dcf4419e652"
dependencies = [
"alloy-json-abi",
"alloy-primitives",
+1 -1
View File
@@ -1,4 +1,4 @@
//! The global configuration used accross all revive differential testing crates.
//! The global configuration used across all revive differential testing crates.
use std::{
fmt::Display,
+1 -1
View File
@@ -12,6 +12,7 @@ rust-version.workspace = true
anyhow = { workspace = true }
alloy = { workspace = true }
tracing = { workspace = true }
tokio = { workspace = true }
revive-dt-node-interaction = { workspace = true }
revive-dt-config = { workspace = true }
@@ -24,4 +25,3 @@ sp-runtime = { workspace = true }
[dev-dependencies]
temp-dir = { workspace = true }
tokio = { workspace = true }
+77 -8
View File
@@ -159,17 +159,85 @@ impl EthereumNode for Instance {
let connection_string = self.connection_string();
let wallet = self.wallet.clone();
tracing::debug!("Submitting transaction: {transaction:#?}");
execute_transaction(Box::pin(async move {
Ok(ProviderBuilder::new()
let outer_span = tracing::debug_span!("Submitting transaction", ?transaction,);
let _outer_guard = outer_span.enter();
let provider = ProviderBuilder::new()
.wallet(wallet)
.connect(&connection_string)
.await?
.send_transaction(transaction)
.await?
.get_receipt()
.await?)
.await?;
let pending_transaction = provider.send_transaction(transaction).await?;
let transaction_hash = pending_transaction.tx_hash();
let span = tracing::info_span!("Awaiting transaction receipt", ?transaction_hash);
let _guard = span.enter();
// The following is a fix for the "transaction indexing is in progress" error that we
// used to get. You can find more information on this in the following GH issue in geth
// https://github.com/ethereum/go-ethereum/issues/28877. To summarize what's going on,
// before we can get the receipt of the transaction it needs to have been indexed by the
// node's indexer. Just because the transaction has been confirmed it doesn't mean that
// it has been indexed. When we call alloy's `get_receipt` it checks if the transaction
// was confirmed. If it has been, then it will call `eth_getTransactionReceipt` method
// which _might_ return the above error if the tx has not yet been indexed yet. So, we
// need to implement a retry mechanism for the receipt to keep retrying to get it until
// it eventually works, but we only do that if the error we get back is the "transaction
// indexing is in progress" error or if the receipt is None.
//
// At the moment we do not allow for the 60 seconds to be modified and we take it as
// being an implementation detail that's invisible to anything outside of this module.
//
// We allow a total of 60 retries for getting the receipt with one second between each
// retry and the next which means that we allow for a total of 60 seconds of waiting
// before we consider that we're unable to get the transaction receipt.
let mut retries = 0;
loop {
match provider.get_transaction_receipt(*transaction_hash).await {
Ok(Some(receipt)) => {
tracing::info!("Obtained the transaction receipt");
break Ok(receipt);
}
Ok(None) => {
if retries == 60 {
tracing::error!(
"Polled for transaction receipt for 60 seconds but failed to get it"
);
break Err(anyhow::anyhow!("Failed to get the transaction receipt"));
} else {
tracing::trace!(
retries,
"Sleeping for 1 second and trying to get the receipt again"
);
retries += 1;
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
continue;
}
}
Err(error) => {
let error_string = error.to_string();
if error_string.contains("transaction indexing is in progress") {
if retries == 60 {
tracing::error!(
"Polled for transaction receipt for 60 seconds but failed to get it"
);
break Err(error.into());
} else {
tracing::trace!(
retries,
"Sleeping for 1 second and trying to get the receipt again"
);
retries += 1;
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
continue;
}
} else {
break Err(error.into());
}
}
}
}
}))
}
@@ -270,6 +338,7 @@ impl Node for Instance {
impl Drop for Instance {
fn drop(&mut self) {
tracing::info!(id = self.id, "Dropping node");
if let Some(child) = self.handle.as_mut() {
let _ = child.kill();
}
+1 -34
View File
@@ -128,7 +128,6 @@ impl KitchensinkNode {
// Start Substrate node
let mut substrate_process = Command::new(&self.substrate_binary)
.arg("--dev")
.arg("--chain")
.arg(chainspec_path)
.arg("--base-path")
@@ -809,14 +808,13 @@ impl BlockHeader for KitchenSinkHeader {
#[cfg(test)]
mod tests {
use alloy::rpc::types::TransactionRequest;
use revive_dt_config::Arguments;
use std::path::PathBuf;
use temp_dir::TempDir;
use std::fs;
use super::*;
use super::KitchensinkNode;
use crate::{GENESIS_JSON, Node};
fn test_config() -> (Arguments, TempDir) {
@@ -831,37 +829,6 @@ mod tests {
(config, temp_dir)
}
#[tokio::test]
async fn node_mines_simple_transfer_transaction_and_returns_receipt() {
// Arrange
let (args, _temp_dir) = test_config();
let mut node = KitchensinkNode::new(&args);
node.spawn(GENESIS_JSON.to_owned())
.expect("Failed to spawn the node");
let provider = ProviderBuilder::new()
.network::<KitchenSinkNetwork>()
.wallet(args.wallet())
.connect(&node.rpc_url)
.await
.expect("Failed to create provider");
let account_address = args.wallet().default_signer().address();
let transaction = TransactionRequest::default()
.to(account_address)
.value(U256::from(100_000_000_000_000u128));
// Act
let receipt = provider.send_transaction(transaction).await;
// Assert
let _ = receipt
.expect("Failed to send the transfer transaction")
.get_receipt()
.await
.expect("Failed to get the receipt for the transfer");
}
#[test]
fn test_init_generates_chainspec_with_balances() {
let genesis_content = r#"