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

build Eip1559 transaction #45

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 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"
47 changes: 34 additions & 13 deletions Node/src/ethereum_l1/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#![allow(unused)] //TODO remove after the EthereumL1 is used in release code

use alloy::{
consensus::transaction::TypedTransaction,
network::{Ethereum, EthereumWallet, NetworkWallet},
primitives::{Address, Bytes, FixedBytes, U256, U32, U64},
providers::ProviderBuilder,
rpc::types::{TransactionInput, TransactionRequest},
signers::local::PrivateKeySigner,
sol,
sol_types::SolValue,
Expand Down Expand Up @@ -54,12 +56,12 @@ impl EthereumL1 {
})
}

pub async fn propose_new_block(
pub async fn create_propose_new_block_tx(
&self,
contract_address: Address,
tx_list: Vec<u8>,
parent_meta_hash: [u8; 32],
) -> Result<(), Error> {
) -> Result<Vec<u8>, Error> {
let provider = ProviderBuilder::new()
.with_recommended_fillers()
.wallet(self.wallet.clone())
Expand All @@ -84,17 +86,34 @@ impl EthereumL1 {

let tx_list = Bytes::from(tx_list);
let lookahead_set_param: Vec<PreconfTaskManager::LookaheadSetParam> = Vec::new();
let builder = contract.newBlockProposal(
encoded_block_params,
tx_list,
U256::from(0),
lookahead_set_param,
);

let tx_hash = builder.send().await?.watch().await?;
tracing::debug!("Proposed new block: {tx_hash}");
let builder = contract
.newBlockProposal(
encoded_block_params,
tx_list,
U256::from(0),
lookahead_set_param,
)
.nonce(1) //TODO how to get it?
.gas(100000)
.max_fee_per_gas(10000000000000000)
.max_priority_fee_per_gas(10000000000000000);

let tx = builder.as_ref().clone().build_typed_tx();
let Ok(TypedTransaction::Eip1559(mut tx)) = tx else {
return Err(anyhow::anyhow!("expect tx in EIP1559"));
};

Ok(())
let signature = self
.wallet
.default_signer()
.sign_transaction(&mut tx)
.await?;

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

Ok(buf)
}

#[cfg(test)]
Expand Down Expand Up @@ -177,8 +196,8 @@ mod tests {
let ethereum_l1 = EthereumL1::new_from_pk(rpc_url, private_key).unwrap();

// some random address for test
ethereum_l1
.propose_new_block(
let encoded_tx = ethereum_l1
.create_propose_new_block_tx(
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
.parse()
.unwrap(),
Expand All @@ -187,5 +206,7 @@ mod tests {
)
.await
.unwrap();

assert!(encoded_tx.len() > 0);
}
}
9 changes: 7 additions & 2 deletions Node/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@ async fn main() -> Result<(), Error> {
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("http://127.0.0.1:1234", "http://127.0.0.1:1235");
let ethereum_l1 = ethereum_l1::EthereumL1::new(
"http://localhost:8545",
"0x4c0883a69102937d6231471b5dbb6204fe512961708279f2e3e8a5d4b8e3e3e8",
)?;
let mev_boost = mev_boost::MevBoost::new("http://localhost:8545");
let node = node::Node::new(node_rx, avs_p2p_tx, taiko, ethereum_l1, mev_boost);
node.entrypoint().await?;
Ok(())
}
Expand Down
17 changes: 17 additions & 0 deletions Node/src/mev_boost/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,18 @@
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
}
}
32 changes: 28 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,
}

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,
}
}

Expand Down Expand Up @@ -67,11 +76,26 @@ impl Node {
.get_pending_l2_tx_lists()
.await
.map_err(Error::from)?;
if pending_tx_lists.tx_list_bytes.len() == 0 {
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?;
let tx = self
.ethereum_l1
.create_propose_new_block_tx(
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
.parse()
.unwrap(),
pending_tx_lists.tx_list_bytes[0].clone(), //TODO: handle rest tx lists
pending_tx_lists.parent_meta_hash,
)
.await?;
self.mev_boost.send_transaction(&tx, 1, 1);
Ok(())
}

Expand Down
117 changes: 117 additions & 0 deletions Node/src/taiko/l2_tx_lists.rs
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is needed because we now have more parameters returned from the proposer by JSON RPC

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,
#[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