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

Prepare transaction list to force push to MEV Boost #88

Merged
merged 7 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
114 changes: 91 additions & 23 deletions Node/src/ethereum_l1/execution_layer.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use super::slot_clock::SlotClock;
use crate::utils::{config, types::*};
use alloy::{
consensus::TypedTransaction,
contract::EventPoller,
network::{Ethereum, EthereumWallet, NetworkWallet},
primitives::{Address, Bytes, FixedBytes, B256, U256},
providers::ProviderBuilder,
providers::{Provider, ProviderBuilder},
signers::{
local::{LocalSigner, PrivateKeySigner},
Signature, SignerSync,
Expand All @@ -23,12 +24,14 @@ use std::sync::Arc;

pub struct ExecutionLayer {
rpc_url: reqwest::Url,
validator_index: u64,
signer: LocalSigner<SigningKey<Secp256k1>>,
wallet: EthereumWallet,
preconfer_address: Address,
contract_addresses: ContractAddresses,
slot_clock: Arc<SlotClock>,
preconf_registry_expiry_sec: u64,
chain_id: u64,
}

pub struct ContractAddresses {
Expand Down Expand Up @@ -126,12 +129,13 @@ sol!(
);

impl ExecutionLayer {
pub fn new(
pub async fn new(
rpc_url: &str,
avs_node_ecdsa_private_key: &str,
contract_addresses: &config::ContractAddresses,
slot_clock: Arc<SlotClock>,
preconf_registry_expiry_sec: u64,
validator_index: u64,
) -> Result<Self, Error> {
tracing::debug!("Creating ExecutionLayer with RPC URL: {}", rpc_url);

Expand All @@ -144,14 +148,19 @@ impl ExecutionLayer {
let contract_addresses = Self::parse_contract_addresses(contract_addresses)
.map_err(|e| Error::msg(format!("Failed to parse contract addresses: {}", e)))?;

let provider = ProviderBuilder::new().on_http(rpc_url.parse()?);
let chain_id = provider.get_chain_id().await?;

Ok(Self {
rpc_url: rpc_url.parse()?,
validator_index,
signer,
wallet,
preconfer_address,
contract_addresses,
slot_clock,
preconf_registry_expiry_sec,
chain_id,
})
}

Expand Down Expand Up @@ -179,18 +188,18 @@ impl ExecutionLayer {

pub async fn propose_new_block(
&self,
nonce: u64,
tx_list: Vec<u8>,
parent_meta_hash: [u8; 32],
lookahead_set: Vec<ProposerDuty>,
) -> Result<(), Error> {
let provider = ProviderBuilder::new()
.with_recommended_fillers()
.wallet(self.wallet.clone())
.on_http(self.rpc_url.clone());
is_send: bool,
) -> Result<Vec<u8>, Error> {
let provider = ProviderBuilder::new().on_http(self.rpc_url.clone());

let contract =
PreconfTaskManager::new(self.contract_addresses.avs.preconf_task_manager, provider);
PreconfTaskManager::new(self.contract_addresses.avs.preconf_task_manager, &provider);

// TODO fix
mikhailUshakoff marked this conversation as resolved.
Show resolved Hide resolved
let block_params = BlockParams {
assignedProver: Address::ZERO,
coinbase: <EthereumWallet as NetworkWallet<Ethereum>>::default_signer_address(
Expand All @@ -207,6 +216,8 @@ impl ExecutionLayer {
let encoded_block_params = Bytes::from(BlockParams::abi_encode_sequence(&block_params));

let tx_list = Bytes::from(tx_list);

// create lookahead set
let lookahead_set_param = lookahead_set
.iter()
.map(|duty| {
Expand All @@ -217,17 +228,50 @@ impl ExecutionLayer {
})
.collect::<Result<Vec<_>, Error>>()?;

let builder = contract.newBlockProposal(
encoded_block_params,
tx_list,
U256::from(0), //TODO: Replace it with the proper lookaheadPointer when the contract is ready.
lookahead_set_param,
);
// TODO check gas parameters
let builder = contract
.newBlockProposal(
encoded_block_params,
tx_list,
U256::from(0), //TODO: Replace it with the proper lookaheadPointer when the contract is ready.
lookahead_set_param,
)
.chain_id(self.chain_id)
.nonce(nonce) //TODO how to get it?
.gas(50_000)
.max_fee_per_gas(20_000_000_000)
.max_priority_fee_per_gas(1_000_000_000);

// Build transaction
let tx = builder.as_ref().clone().build_typed_tx();
let Ok(TypedTransaction::Eip1559(mut tx)) = tx else {
// TODO fix
panic!("Not EIP1559 transaction");
};

let tx_hash = builder.send().await?.watch().await?;
tracing::debug!("Proposed new block: {tx_hash}");
// Sign transaction
let signature = self
.wallet
.default_signer()
.sign_transaction(&mut tx)
.await?;

Ok(())
// Encode transaction
let mut buf = vec![];
tx.encode_with_signature(&signature, &mut buf, false);

// Send transaction
if is_send {
let pending = provider
.send_raw_transaction(&buf)
.await?
.register()
.await?;

tracing::debug!("Proposed new block, with hash {}", pending.tx_hash());
}

Ok(buf)
}

pub async fn register_preconfer(&self) -> Result<(), Error> {
Expand Down Expand Up @@ -319,6 +363,15 @@ impl ExecutionLayer {
Ok(address)
}

pub async fn get_preconfer_nonce(&self) -> Result<u64, Error> {
let provider = ProviderBuilder::new().on_http(self.rpc_url.clone());

let nonce = provider
.get_transaction_count(self.preconfer_address)
.await?;
Ok(nonce)
}

pub async fn prove_incorrect_preconfirmation(
&self,
block_id: u64,
Expand Down Expand Up @@ -410,7 +463,7 @@ impl ExecutionLayer {
let params = contract
.getLookaheadParamsForEpoch(
U256::from(epoch_begin_timestamp),
validator_bls_pub_keys.map(|key| Bytes::from(key)),
validator_bls_pub_keys.map(Bytes::from),
)
.call()
.await?
Expand All @@ -437,16 +490,20 @@ impl ExecutionLayer {
}

#[cfg(test)]
pub fn new_from_pk(
pub async fn new_from_pk(
rpc_url: reqwest::Url,
private_key: elliptic_curve::SecretKey<k256::Secp256k1>,
) -> Result<Self, Error> {
let signer = PrivateKeySigner::from_signing_key(private_key.into());
let wallet = EthereumWallet::from(signer.clone());
let clock = SlotClock::new(0u64, 0u64, 12u64, 32u64);

let provider = ProviderBuilder::new().on_http(rpc_url.clone());
let chain_id = provider.get_chain_id().await?;

Ok(Self {
rpc_url,
validator_index: 0,
signer,
wallet,
preconfer_address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" // some random address for test
Expand All @@ -465,6 +522,7 @@ impl ExecutionLayer {
},
},
preconf_registry_expiry_sec: 120,
chain_id,
})
}

Expand Down Expand Up @@ -508,6 +566,10 @@ impl ExecutionLayer {

Ok(())
}

pub fn get_validator_index(&self) -> u64 {
self.validator_index
}
}

#[cfg(test)]
Expand All @@ -521,7 +583,9 @@ mod tests {
let anvil = Anvil::new().try_spawn().unwrap();
let rpc_url: reqwest::Url = anvil.endpoint().parse().unwrap();
let private_key = anvil.keys()[0].clone();
let el = ExecutionLayer::new_from_pk(rpc_url, private_key).unwrap();
let el = ExecutionLayer::new_from_pk(rpc_url, private_key)
.await
.unwrap();
el.call_test_contract().await.unwrap();
}

Expand All @@ -530,9 +594,11 @@ mod tests {
let anvil = Anvil::new().try_spawn().unwrap();
let rpc_url: reqwest::Url = anvil.endpoint().parse().unwrap();
let private_key = anvil.keys()[0].clone();
let el = ExecutionLayer::new_from_pk(rpc_url, private_key).unwrap();
let el = ExecutionLayer::new_from_pk(rpc_url, private_key)
.await
.unwrap();

el.propose_new_block(vec![0; 32], [0; 32], vec![])
el.propose_new_block(0, vec![0; 32], [0; 32], vec![], true)
.await
.unwrap();
}
Expand All @@ -541,7 +607,9 @@ mod tests {
let anvil = Anvil::new().try_spawn().unwrap();
let rpc_url: reqwest::Url = anvil.endpoint().parse().unwrap();
let private_key = anvil.keys()[0].clone();
let el = ExecutionLayer::new_from_pk(rpc_url, private_key).unwrap();
let el = ExecutionLayer::new_from_pk(rpc_url, private_key)
.await
.unwrap();

let result = el.register_preconfer().await;
assert!(result.is_ok(), "Register method failed: {:?}", result.err());
Expand Down
11 changes: 8 additions & 3 deletions Node/src/ethereum_l1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ impl EthereumL1 {
slot_duration_sec: u64,
slots_per_epoch: u64,
preconf_registry_expiry_sec: u64,
validator_index: u64,
) -> Result<Self, anyhow::Error> {
let consensus_layer = ConsensusLayer::new(consensus_rpc_url)?;
let genesis_details = consensus_layer.get_genesis_details().await?;
Expand All @@ -39,7 +40,9 @@ impl EthereumL1 {
contract_addresses,
slot_clock.clone(),
preconf_registry_expiry_sec,
)?;
validator_index,
)
.await?;

Ok(Self {
slot_clock,
Expand All @@ -64,9 +67,11 @@ mod tests {
let anvil = Anvil::new().try_spawn().unwrap();
let rpc_url: reqwest::Url = anvil.endpoint().parse().unwrap();
let private_key = anvil.keys()[0].clone();
let el = ExecutionLayer::new_from_pk(rpc_url, private_key).unwrap();
let el = ExecutionLayer::new_from_pk(rpc_url, private_key)
.await
.unwrap();

el.propose_new_block(vec![0; 32], [0; 32], duties)
el.propose_new_block(0, vec![0; 32], [0; 32], duties, true)
.await
.unwrap();
}
Expand Down
2 changes: 2 additions & 0 deletions Node/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ async fn main() -> Result<(), Error> {
config.l1_slot_duration_sec,
config.l1_slots_per_epoch,
config.preconf_registry_expiry_sec,
config.validator_index,
mikhailUshakoff marked this conversation as resolved.
Show resolved Hide resolved
)
.await?;

Expand All @@ -60,6 +61,7 @@ async fn main() -> Result<(), Error> {
BlockProposedEventReceiver::new(taiko.clone(), node_tx.clone());
BlockProposedEventReceiver::start(block_proposed_event_checker).await;
let ethereum_l1 = Arc::new(ethereum_l1);

let node = node::Node::new(
node_rx,
node_to_p2p_tx,
Expand Down
48 changes: 48 additions & 0 deletions Node/src/mev_boost/constraints.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Clone)]
pub struct Constraint {
tx: String,
index: Option<u64>,
}

impl Constraint {
pub fn new(tx: String, index: Option<u64>) -> Self {
Self { tx, index }
}
}

#[derive(Serialize, Deserialize, Clone)]
pub struct ConstraintsMessage {
validator_index: u64,
slot: u64,
constraints: Vec<Constraint>,
}

impl ConstraintsMessage {
pub fn new(validator_index: u64, slot: u64, constraints: Vec<Constraint>) -> Self {
Self {
validator_index,
slot,
constraints,
}
}
}

#[derive(Serialize, Deserialize, Clone)]
pub struct SignedConstraints {
message: ConstraintsMessage,
signature: String,
}

impl SignedConstraints {
pub fn new(message: ConstraintsMessage, signature: String) -> Self {
Self { message, signature }
}
}

impl From<ConstraintsMessage> for Vec<u8> {
fn from(val: ConstraintsMessage) -> Self {
bincode::serialize(&val).expect("MEV Boost message serialization failed")
}
}
Loading