Skip to content
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: interval mining #4619

Merged
merged 2 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions crates/edr_napi/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,13 +238,13 @@ export interface MemPoolConfig {
order: MineOrdering
}
export interface IntervalRange {
min: number
max: number
min: bigint
max: bigint
}
/** Configuration for the provider's miner. */
export interface MiningConfig {
autoMine: boolean
interval: number | IntervalRange
interval?: bigint | IntervalRange
memPool: MemPoolConfig
}
/** Configuration for a provider */
Expand Down
40 changes: 26 additions & 14 deletions crates/edr_napi/src/provider/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ pub struct MemPoolConfig {

#[napi(object)]
pub struct IntervalRange {
pub min: i64,
pub max: i64,
pub min: BigInt,
pub max: BigInt,
}

/// Configuration for the provider's miner.
#[napi(object)]
pub struct MiningConfig {
pub auto_mine: bool,
pub interval: Either<i64, IntervalRange>,
pub interval: Option<Either<BigInt, IntervalRange>>,
pub mem_pool: MemPoolConfig,
}

Expand Down Expand Up @@ -106,22 +106,34 @@ impl From<MemPoolConfig> for edr_provider::MemPoolConfig {
}
}

impl From<MiningConfig> for edr_provider::MiningConfig {
fn from(value: MiningConfig) -> Self {
impl TryFrom<MiningConfig> for edr_provider::MiningConfig {
type Error = napi::Error;

fn try_from(value: MiningConfig) -> Result<Self, Self::Error> {
let mem_pool = value.mem_pool.into();

let interval = match value.interval {
Either::A(interval) => edr_provider::IntervalConfig::Fixed(interval),
Either::B(IntervalRange { min, max }) => {
edr_provider::IntervalConfig::Range { min, max }
}
};
let interval = value
.interval
.map(|interval| {
let interval = match interval {
Either::A(interval) => {
edr_provider::IntervalConfig::Fixed(interval.try_cast()?)
}
Either::B(IntervalRange { min, max }) => edr_provider::IntervalConfig::Range {
min: min.try_cast()?,
max: max.try_cast()?,
},
};

napi::Result::Ok(interval)
})
.transpose()?;

Self {
Ok(Self {
auto_mine: value.auto_mine,
interval,
mem_pool,
}
})
}
}

Expand Down Expand Up @@ -164,7 +176,7 @@ impl TryFrom<ProviderConfig> for edr_provider::ProviderConfig {
.initial_parent_beacon_block_root
.map(TryCast::try_cast)
.transpose()?,
mining: value.mining.into(),
mining: value.mining.try_into()?,
network_id: value.network_id.try_cast()?,
})
}
Expand Down
2 changes: 2 additions & 0 deletions crates/edr_provider/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ edr_evm = { version = "0.2.0-dev", path = "../edr_evm" }
rpc_hardhat = { package = "edr_rpc_hardhat", version = "0.2.0-dev", path = "../edr_rpc_hardhat" }
indexmap = { version = "2.0.0", default-features = false, features = ["std"] }
k256 = { version = "0.13.1", default-features = false, features = ["arithmetic", "ecdsa", "pkcs8", "precomputed-tables", "std"] }
log = { version = "0.4.20", default-features = false }
parking_lot = { version = "0.12.1", default-features = false }
rand = { version = "0.8.5", default-features = false }
rlp = { version = "0.5.2", default-features = false }
serde = { version = "1.0.147", default-features = false, features = ["derive"] }
serde_json = { version = "1.0.89" }
Expand Down
21 changes: 17 additions & 4 deletions crates/edr_provider/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,24 @@ use std::{path::PathBuf, time::SystemTime};

use edr_eth::{block::BlobGas, AccountInfo, Address, HashMap, SpecId, B256, U256};
use edr_evm::MineOrdering;
use rand::Rng;
use rpc_hardhat::config::ForkConfig;

/// Configuration for interval mining.
#[derive(Clone)]
pub enum IntervalConfig {
Fixed(i64),
Range { min: i64, max: i64 },
Fixed(u64),
Range { min: u64, max: u64 },
}

impl IntervalConfig {
/// Generates a (random) interval based on the configuration.
pub fn generate_interval(&self) -> u64 {
match self {
IntervalConfig::Fixed(interval) => *interval,
IntervalConfig::Range { min, max } => rand::thread_rng().gen_range(*min..=*max),
}
}
}

/// Configuration for the provider's mempool.
Expand All @@ -17,7 +30,7 @@ pub struct MemPoolConfig {
/// Configuration for the provider's miner.
pub struct MiningConfig {
pub auto_mine: bool,
pub interval: IntervalConfig,
pub interval: Option<IntervalConfig>,
pub mem_pool: MemPoolConfig,
}

Expand Down Expand Up @@ -62,7 +75,7 @@ impl Default for MiningConfig {
fn default() -> Self {
Self {
auto_mine: true,
interval: IntervalConfig::Fixed(0),
interval: None,
mem_pool: MemPoolConfig::default(),
}
}
Expand Down
25 changes: 25 additions & 0 deletions crates/edr_provider/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,31 @@ impl ProviderData {
&self.instance_id
}

pub fn interval_mine(&mut self) -> Result<bool, ProviderError> {
let result = self.mine_and_commit_block(None)?;

let header = result.block.header();
let is_empty = result.block.transactions().is_empty();
if is_empty {
self.logger.print_interval_mined_block_number(
header.number,
is_empty,
header.base_fee_per_gas,
);
} else {
log::error!("TODO: interval_mine: log mined block");
Wodann marked this conversation as resolved.
Show resolved Hide resolved

self.logger
.print_interval_mined_block_number(header.number, is_empty, None);

if self.logger.print_logs() {
self.logger.print_empty_line();
}
}

Ok(true)
}

pub fn logger(&self) -> &Logger {
&self.logger
}
Expand Down
78 changes: 78 additions & 0 deletions crates/edr_provider/src/interval.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use std::sync::Arc;

use parking_lot::Mutex;
use tokio::{runtime, sync::oneshot, task::JoinHandle};

use crate::{data::ProviderData, IntervalConfig, ProviderError};

/// Type for interval mining on a separate thread.
pub struct IntervalMiner {
inner: Option<Inner>,
runtime: runtime::Handle,
}

/// Inner type for interval mining on a separate thread, required for
/// implementation of `Drop`.
struct Inner {
cancellation_sender: oneshot::Sender<()>,
background_task: JoinHandle<Result<(), ProviderError>>,
}

impl IntervalMiner {
pub fn new(
runtime: runtime::Handle,
config: IntervalConfig,
data: Arc<Mutex<ProviderData>>,
) -> Self {
let (cancellation_sender, mut cancellation_receiver) = oneshot::channel();
let background_task = tokio::spawn(async move {
loop {
let delay = config.generate_interval();

tokio::select! {
_ = &mut cancellation_receiver => return Ok(()),
_ = tokio::time::sleep(std::time::Duration::from_secs(delay)) => {
let data = data.clone();

runtime::Handle::current().spawn_blocking(move ||{
let mut data = data.lock();
if let Err(error) = data.interval_mine() {
log::error!("Unexpected error while performing interval mining: {error}");
return Err(error);
}

Ok(())
}).await.expect("Failed to join interval mining task")
},
}?;
}
});

Self {
inner: Some(Inner {
cancellation_sender,
background_task,
}),
runtime,
}
}
}

impl Drop for IntervalMiner {
fn drop(&mut self) {
if let Some(Inner {
cancellation_sender,
background_task: task,
}) = self.inner.take()
{
cancellation_sender
.send(())
.expect("Failed to send cancellation signal");

let _result = self
.runtime
.block_on(task)
.expect("Failed to join interval mininig task");
}
}
}
25 changes: 20 additions & 5 deletions crates/edr_provider/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,24 @@ mod config;
mod data;
mod error;
mod filter;
mod interval;
mod logger;
mod requests;
/// Test utilities
#[cfg(test)]
pub mod test_utils;

use data::{CreationError, ProviderData};
use std::sync::Arc;

use parking_lot::Mutex;
use requests::{eth, hardhat};
use tokio::runtime;

use self::requests::{EthRequest, Request};
pub use self::{config::*, error::ProviderError, requests::ProviderRequest};
use self::{
data::{CreationError, ProviderData},
interval::IntervalMiner,
requests::{eth, hardhat, EthRequest, Request},
};

/// A JSON-RPC provider for Ethereum.
///
Expand Down Expand Up @@ -47,7 +52,9 @@ pub use self::{config::*, error::ProviderError, requests::ProviderRequest};
/// }
/// ```
pub struct Provider {
data: Mutex<ProviderData>,
data: Arc<Mutex<ProviderData>>,
/// Interval miner runs in the background, if enabled.
_interval_miner: Option<IntervalMiner>,
}

impl Provider {
Expand All @@ -57,9 +64,17 @@ impl Provider {
config: &ProviderConfig,
) -> Result<Self, CreationError> {
let data = ProviderData::new(runtime, config).await?;
let data = Arc::new(Mutex::new(data));

let interval_miner = config
.mining
.interval
.as_ref()
.map(|config| IntervalMiner::new(runtime.clone(), config.clone(), data.clone()));

Ok(Self {
data: Mutex::new(data),
data,
_interval_miner: interval_miner,
})
}

Expand Down
4 changes: 3 additions & 1 deletion crates/edr_provider/src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ impl Logger {
pub fn print_method(&self, _method: &str) {}

/// Prints all accumulated logs.
pub fn print_logs(&self) {}
pub fn print_logs(&self) -> bool {
false
}

/// Prints the block number of an interval-mined block.
pub fn print_interval_mined_block_number(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ import {
SuccessReason,
IntervalRange,
} from "@ignored/edr";
import { isNumber } from "lodash";
import { fromBigIntLike, toHex } from "../../../util/bigint";
import { HardforkName, hardforkGte } from "../../../util/hardforks";
import {
Expand Down Expand Up @@ -262,13 +261,18 @@ export function ethereumjsHeaderDataToEdrBlockOptions(

export function ethereumjsIntervalMiningConfigToEdr(
config: IntervalMiningConfig
): number | IntervalRange {
if (isNumber(config)) {
return config;
): bigint | IntervalRange | undefined {
if (typeof config === "number") {
// Is interval mining disabled?
if (config === 0) {
return undefined;
} else {
return BigInt(config);
}
} else {
return {
min: config[0],
max: config[1],
min: BigInt(config[0]),
max: BigInt(config[1]),
};
}
}
Expand Down
Loading