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

Send new block proposal by raw tx #47

Merged
merged 6 commits into from
Jul 5, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
1 change: 1 addition & 0 deletions Node/Cargo.lock

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

2 changes: 1 addition & 1 deletion Node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ anyhow = "1.0.86"
k256 = "0.13"
elliptic-curve = "0.13"
reqwest = "0.12"

hex = "0.4"
37 changes: 17 additions & 20 deletions Node/src/ethereum_l1/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#![allow(unused)] //TODO remove after the EthereumL1 is used in release code

use alloy::{
network::{Ethereum, EthereumWallet, NetworkWallet},
primitives::{Address, Bytes, FixedBytes, U256, U32, U64},
primitives::{Address, Bytes, FixedBytes, U256},
providers::ProviderBuilder,
signers::local::PrivateKeySigner,
sol,
Expand All @@ -14,6 +12,7 @@ use std::str::FromStr;
pub struct EthereumL1 {
rpc_url: reqwest::Url,
wallet: EthereumWallet,
new_block_proposal_contract_address: Address,
}

sol!(
Expand Down Expand Up @@ -44,19 +43,23 @@ sol! {
}

impl EthereumL1 {
pub fn new(rpc_url: &str, private_key: &str) -> Result<Self, Error> {
pub fn new(
rpc_url: &str,
private_key: &str,
new_block_proposal_contract_address: &str,
) -> Result<Self, Error> {
let signer = PrivateKeySigner::from_str(private_key)?;
let wallet = EthereumWallet::from(signer);

Ok(Self {
rpc_url: rpc_url.parse()?,
wallet,
new_block_proposal_contract_address: new_block_proposal_contract_address.parse()?,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: let's call it the taiko_preconfirming_address

})
}

pub async fn propose_new_block(
&self,
contract_address: Address,
tx_list: Vec<u8>,
parent_meta_hash: [u8; 32],
) -> Result<(), Error> {
Expand All @@ -65,7 +68,7 @@ impl EthereumL1 {
.wallet(self.wallet.clone())
.on_http(self.rpc_url.clone());

let contract = PreconfTaskManager::new(contract_address, provider);
let contract = PreconfTaskManager::new(self.new_block_proposal_contract_address, provider);

let block_params = BlockParams {
assignedProver: Address::ZERO,
Expand Down Expand Up @@ -105,7 +108,12 @@ impl EthereumL1 {
let signer = PrivateKeySigner::from_signing_key(private_key.into());
let wallet = EthereumWallet::from(signer);

Ok(Self { rpc_url, wallet })
Ok(Self {
rpc_url,
wallet,
new_block_proposal_contract_address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" // some random address for test
.parse()?,
})
}

#[cfg(test)]
Expand All @@ -132,7 +140,6 @@ impl EthereumL1 {
.on_http(self.rpc_url.clone());

let contract = Counter::deploy(&provider).await?;
let address = contract.address().clone();

let builder = contract.setNumber(U256::from(42));
let tx_hash = builder.send().await?.watch().await?;
Expand All @@ -154,10 +161,7 @@ impl EthereumL1 {
#[cfg(test)]
mod tests {
use super::*;
use alloy::hex;
use alloy::node_bindings::{Anvil, AnvilInstance};
use alloy::providers::Provider;
use alloy::rpc::types::TransactionRequest;
use alloy::node_bindings::Anvil;

#[tokio::test]
async fn test_call_contract() {
Expand All @@ -176,15 +180,8 @@ mod tests {
let private_key = anvil.keys()[0].clone();
let ethereum_l1 = EthereumL1::new_from_pk(rpc_url, private_key).unwrap();

// some random address for test
ethereum_l1
.propose_new_block(
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
.parse()
.unwrap(),
vec![0; 32],
[0; 32],
)
.propose_new_block(vec![0; 32], [0; 32])
.await
.unwrap();
}
Expand Down
11 changes: 9 additions & 2 deletions Node/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,20 @@ const MESSAGE_QUEUE_SIZE: usize = 100;
#[tokio::main]
async fn main() -> Result<(), Error> {
init_logging();
let config = utils::config::Config::read_env_variables();

let (avs_p2p_tx, avs_p2p_rx) = mpsc::channel(MESSAGE_QUEUE_SIZE);
let (node_tx, node_rx) = mpsc::channel(MESSAGE_QUEUE_SIZE);
let p2p = p2p_network::AVSp2p::new(node_tx.clone(), avs_p2p_rx);
p2p.start();

let node = node::Node::new(node_rx, avs_p2p_tx);
let taiko = taiko::Taiko::new(&config.taiko_proposer_url, &config.taiko_driver_url);
let ethereum_l1 = ethereum_l1::EthereumL1::new(
&config.mev_boost_url,
&config.ethereum_private_key,
&config.new_block_proposal_contract_address,
)?;
let mev_boost = mev_boost::MevBoost::new(&config.mev_boost_url);
mskrzypkows marked this conversation as resolved.
Show resolved Hide resolved
let node = node::Node::new(node_rx, avs_p2p_tx, taiko, ethereum_l1, mev_boost);
node.entrypoint().await?;
Ok(())
}
Expand Down
19 changes: 19 additions & 0 deletions Node/src/mev_boost/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,20 @@
#![allow(unused)] //TODO remove after the EthereumL1 is used in release code

use crate::utils::rpc_client::RpcClient;

pub struct MevBoost {
_rpc_client: RpcClient,
}

impl MevBoost {
pub fn new(rpc_url: &str) -> Self {
let rpc_client = RpcClient::new(rpc_url);
Self {
_rpc_client: rpc_client,
}
}

pub fn send_transaction(&self, _tx: &[u8], _validator_index: u64, _slot: u64) {
//TODO: implement
}
}
27 changes: 23 additions & 4 deletions Node/src/node/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::taiko::Taiko;
use crate::{ethereum_l1::EthereumL1, mev_boost::MevBoost, taiko::Taiko};
use anyhow::{anyhow as any_err, Error, Ok};
use tokio::sync::mpsc::{Receiver, Sender};

Expand All @@ -7,16 +7,25 @@ pub struct Node {
node_rx: Option<Receiver<String>>,
avs_p2p_tx: Sender<String>,
gas_used: u64,
ethereum_l1: EthereumL1,
_mev_boost: MevBoost, // temporary unused
}

impl Node {
pub fn new(node_rx: Receiver<String>, avs_p2p_tx: Sender<String>) -> Self {
let taiko = Taiko::new("http://127.0.0.1:1234", "http://127.0.0.1:1235");
pub fn new(
node_rx: Receiver<String>,
avs_p2p_tx: Sender<String>,
taiko: Taiko,
ethereum_l1: EthereumL1,
mev_boost: MevBoost,
) -> Self {
Self {
taiko,
node_rx: Some(node_rx),
avs_p2p_tx,
gas_used: 0,
ethereum_l1,
_mev_boost: mev_boost,
}
}

Expand Down Expand Up @@ -67,10 +76,20 @@ impl Node {
.get_pending_l2_tx_lists()
.await
.map_err(Error::from)?;
if pending_tx_lists.tx_list_bytes.is_empty() {
return Ok(());
}

self.commit_to_the_tx_lists();
self.send_preconfirmations_to_the_avs_p2p().await?;
self.taiko
.advance_head_to_new_l2_block(pending_tx_lists, self.gas_used)
.advance_head_to_new_l2_block(pending_tx_lists.tx_lists, self.gas_used)
.await?;
self.ethereum_l1
.propose_new_block(
mskrzypkows marked this conversation as resolved.
Show resolved Hide resolved
pending_tx_lists.tx_list_bytes[0].clone(), //TODO: handle rest tx lists
pending_tx_lists.parent_meta_hash,
)
.await?;
Ok(())
}
Expand Down
117 changes: 117 additions & 0 deletions Node/src/taiko/l2_tx_lists.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use anyhow::Error;
use serde::{Deserialize, Deserializer, Serialize};
use serde_json::Value;

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct RPCReplyL2TxLists {
pub tx_lists: Value,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my preference would be to put the correct type instead of Value but happy to skip if its too much for devnet
let's put a TODO here otherwise

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, but this is in the json::Value form because I pass directly the same json to the driver to advance the head, so after parsing it to the type I would need to encode it for driver.

#[serde(deserialize_with = "deserialize_tx_lists_bytes")]
pub tx_list_bytes: Vec<Vec<u8>>,
#[serde(deserialize_with = "deserialize_parent_meta_hash")]
pub parent_meta_hash: [u8; 32],
}

fn deserialize_tx_lists_bytes<'de, D>(deserializer: D) -> Result<Vec<Vec<u8>>, D::Error>
where
D: Deserializer<'de>,
{
let vec: Vec<String> = Deserialize::deserialize(deserializer)?;
let result = vec
.iter()
.map(|s| s.as_bytes().to_vec())
.collect::<Vec<Vec<u8>>>();
Ok(result)
}

fn deserialize_parent_meta_hash<'de, D>(deserializer: D) -> Result<[u8; 32], D::Error>
where
D: Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?;
let s = s.trim_start_matches("0x");
let bytes = hex::decode(s).map_err(serde::de::Error::custom)?;
if bytes.len() != 32 {
return Err(serde::de::Error::custom(
"Invalid length for parent_meta_hash",
));
}
let mut array = [0u8; 32];
array.copy_from_slice(&bytes);
Ok(array)
}

pub fn decompose_pending_lists_json(json: Value) -> Result<RPCReplyL2TxLists, Error> {
// Deserialize the JSON string into the struct
let rpc_reply: RPCReplyL2TxLists = serde_json::from_value(json)?;
Ok(rpc_reply)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_decompose_pending_lists_json() {
let json_data = serde_json::json!(
{
"TxLists": [
[
{
"type": "0x0",
"chainId": "0x28c61",
"nonce": "0x8836",
"to": "0x8b14d287b4150ff22ac73df8be720e933f659abc",
"gas": "0x35f30",
"gasPrice": "0xf4b87001",
"maxPriorityFeePerGas": null,
"maxFeePerGas": null,
"value": "0x0",
"input": "0x3161b7f60000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000027e9000000000000000000000000000000000000000000000005751b6fc9babade290000000000000000000000000000000000000000000000000000000008f811330000000000000000000000000000000000000000000000000000000000000010",
"v": "0x518e5",
"r": "0xb7b4b5540e08775ebb3c077ca7d572378cdb6ed55e3387173f8248578cc073e9",
"s": "0x1f8860f90b61202d4070d1eba494d38c2cb02c749ea1ec542c8d02e5ceeb6439",
"hash": "0xc653e446eafe51eea1f46e6e351adbd1cc8a3271e6935f1441f613a58d441f6a"
},
{
"type": "0x2",
"chainId": "0x28c61",
"nonce": "0x26d0",
"to": "0x2f6ef5baae08ae9df23528c217a77f03f93b690e",
"gas": "0x1a09b",
"gasPrice": null,
"maxPriorityFeePerGas": "0xcbef0801",
"maxFeePerGas": "0xcbef0801",
"value": "0x0",
"input": "0xbb2cd728000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000ae2c46ddb314b9ba743c6dee4878f151881333d90000000000000000000000007d16e966c879ed6ad9972ddd5376c41a427d2c2a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000004cd712049c0000000000000000000000000000000000000000000000000000057b3ac2af84",
"accessList": [],
"v": "0x0",
"r": "0xbfc407896ee6ed36962d1a591b41aa9a17fe19e176e61cb54a1cd69e3a337508",
"s": "0x621b2448dda4d797447935c051e3908f65dfb3729415280a04cb02c4474baefe",
"yParity": "0x0",
"hash": "0xffbcd2fab90f1bf314ca2da1bf83eeab3d17fd58a0393d29a697b2ff05d0e65c"
}
]
],
"TxListBytes": [
"eJz6ybTuJ6NeU4dZy5cdBYzNzPEGU7pFLrVvEeX/pHXc9se+Ir7J9qmz9jTsOGKYuP0bA36gQECeEb+0+kscEqyl0vknd+26p4lPN8cPQWMC9gs0s0o8XbB9y9YQPo7yuN027DXLrxaZ99zOuxpn3C5u3+QR3nOg+OUC+Y6En9yJCroOBRdfL5lyuUdng07JvIVvQnR6mZ6ee51iuZOxiuknY1kzU09ik9qFltPvORjBRDPjgtlT9PO+7lrHsW7uJ1ONQ+LL65l/WmfyNexkZNmtc12DgPMcCMgvICDPhMxZp+N2d7PIzl0lNrnvPCo+BnYIG99Elq8Ve5l2ovJt1s3puneDy45IOdXqaJFiPhrwuS7EMge3NGu11aH1LQcaFuw/wt6Z9+yt2TRdqUhpx1WzxP9JPix7JrPVS+baPCvjUo4FSdIqHneXXJ/uUml6IPDxhP7U+5uLpohqcLGcZjri7r3uHyAAAP//huiQHQ=="
],
"ParentMetaHash": "0x2bcf3b1bb0c4066aa46ba6e99b79d7602f124d5ae8fcffd2977b1c2138aa61bc"
}
);

let result = decompose_pending_lists_json(json_data).unwrap();

assert_eq!(result.tx_lists.as_array().unwrap().len(), 1);
assert_eq!(
result.tx_lists.as_array().unwrap()[0]
.as_array()
.unwrap()
.len(),
2
);
assert_eq!(result.tx_list_bytes.len(), 1);
assert_eq!(result.tx_list_bytes[0].len(), 492);
assert_eq!(result.parent_meta_hash.len(), 32);
}
}
Loading