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(core): Adds support for 4844 transaction signing and rlp encoding #1254

Merged
merged 9 commits into from
Feb 26, 2024
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
3 changes: 3 additions & 0 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions core/lib/eth_client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ serde = "1.0.90"
thiserror = "1"
async-trait = "0.1"
tracing = "0.1"
rlp = "0.5"

[dev-dependencies]
static_assertions = "1.1.0"
tokio = { version = "1", features = ["full"] }
pretty_assertions = "1"
hex = "0.4.2"
3 changes: 1 addition & 2 deletions core/lib/eth_client/src/clients/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use std::sync::Arc;
use async_trait::async_trait;
use zksync_types::{
web3::{
contract::Options,
ethabi,
types::{
Address, Block, BlockId, BlockNumber, Filter, Log, Transaction, TransactionReceipt,
Expand All @@ -14,7 +13,7 @@ use zksync_types::{
};

use crate::{
BoundEthInterface, ContractCall, Error, EthInterface, ExecutedTxStatus, FailureInfo,
BoundEthInterface, ContractCall, Error, EthInterface, ExecutedTxStatus, FailureInfo, Options,
RawTransactionBytes, SignedCallResult,
};

Expand Down
34 changes: 25 additions & 9 deletions core/lib/eth_client/src/clients/http/signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@ use zksync_eth_signer::{raw_ethereum_tx::TransactionParameters, EthereumSigner,
use zksync_types::{
web3::{
self,
contract::{tokens::Detokenize, Options},
contract::tokens::Detokenize,
ethabi,
transports::Http,
types::{
Address, Block, BlockId, BlockNumber, Filter, Log, Transaction, TransactionReceipt,
H160, H256, U256, U64,
},
},
L1ChainId, PackedEthSignature, EIP_1559_TX_TYPE,
L1ChainId, PackedEthSignature, EIP_4844_TX_TYPE,
};

use super::{query::QueryClient, Method, LATENCIES};
use crate::{
types::{Error, ExecutedTxStatus, FailureInfo, SignedCallResult},
BoundEthInterface, CallFunctionArgs, ContractCall, EthInterface, RawTransactionBytes,
types::{encode_blob_tx_with_sidecar, Error, ExecutedTxStatus, FailureInfo, SignedCallResult},
BoundEthInterface, CallFunctionArgs, ContractCall, EthInterface, Options, RawTransactionBytes,
};

/// HTTP-based Ethereum client, backed by a private key to sign transactions.
Expand Down Expand Up @@ -259,6 +259,15 @@ impl<S: EthereumSigner> BoundEthInterface for SigningClient<S> {
None => self.inner.default_priority_fee_per_gas,
};

if options.transaction_type == Some(EIP_4844_TX_TYPE.into()) {
if options.max_fee_per_blob_gas.is_none() {
return Err(Error::Eip4844MissingMaxFeePerBlobGas);
}
if options.blob_versioned_hashes.is_none() {
return Err(Error::Eip4844MissingBlobVersionedHashes);
}
}

// Fetch current base fee and add `max_priority_fee_per_gas`
let max_fee_per_gas = match options.max_fee_per_gas {
Some(max_fee_per_gas) => max_fee_per_gas,
Expand Down Expand Up @@ -300,21 +309,28 @@ impl<S: EthereumSigner> BoundEthInterface for SigningClient<S> {
chain_id: self.inner.chain_id.0,
max_priority_fee_per_gas,
gas_price: None,
transaction_type: Some(EIP_1559_TX_TYPE.into()),
transaction_type: options.transaction_type,
access_list: None,
max_fee_per_gas,
max_fee_per_blob_gas: options.max_fee_per_blob_gas,
blob_versioned_hashes: options.blob_versioned_hashes,
};

let signed_tx = self.inner.eth_signer.sign_transaction(tx).await?;
let mut signed_tx = self.inner.eth_signer.sign_transaction(tx).await?;
let hash = web3::signing::keccak256(&signed_tx).into();
latency.observe();
Ok(SignedCallResult {
raw_tx: RawTransactionBytes(signed_tx),

if let Some(sidecar) = options.blob_tx_sidecar {
signed_tx = encode_blob_tx_with_sidecar(&signed_tx, &sidecar);
}

Ok(SignedCallResult::new(
RawTransactionBytes(signed_tx),
max_priority_fee_per_gas,
max_fee_per_gas,
nonce,
hash,
})
))
}

async fn allowance_on_account(
Expand Down
14 changes: 7 additions & 7 deletions core/lib/eth_client/src/clients/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use async_trait::async_trait;
use jsonrpc_core::types::error::Error as RpcError;
use zksync_types::{
web3::{
contract::{tokens::Tokenize, Options},
contract::tokens::Tokenize,
ethabi,
types::{Block, BlockId, BlockNumber, Filter, Log, Transaction, TransactionReceipt, U64},
Error as Web3Error,
Expand All @@ -17,7 +17,7 @@ use zksync_types::{

use crate::{
types::{Error, ExecutedTxStatus, FailureInfo, SignedCallResult},
BoundEthInterface, ContractCall, EthInterface, RawTransactionBytes,
BoundEthInterface, ContractCall, EthInterface, Options, RawTransactionBytes,
};

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -187,13 +187,13 @@ impl MockEthereum {
// Concatenate `raw_tx` plus hash for test purposes
let mut new_raw_tx = hash.as_bytes().to_vec();
new_raw_tx.extend(raw_tx);
Ok(SignedCallResult {
raw_tx: RawTransactionBytes(new_raw_tx),
Ok(SignedCallResult::new(
RawTransactionBytes(new_raw_tx),
max_priority_fee_per_gas,
max_fee_per_gas,
nonce,
hash,
})
))
}

pub fn advance_block_number(&self, val: u64) -> u64 {
Expand Down Expand Up @@ -448,15 +448,15 @@ mod tests {
b"test".to_vec(),
Options {
nonce: Some(1.into()),
..Options::default()
..Default::default()
},
)
.unwrap();
assert_eq!(signed_tx.nonce, 1.into());
assert!(signed_tx.max_priority_fee_per_gas > 0.into());
assert!(signed_tx.max_fee_per_gas > 0.into());

let tx_hash = client.send_raw_tx(signed_tx.raw_tx).await.unwrap();
let tx_hash = client.send_raw_tx(signed_tx.raw_tx.clone()).await.unwrap();
assert_eq!(tx_hash, signed_tx.hash);

client.execute_tx(tx_hash, true, 3);
Expand Down
47 changes: 44 additions & 3 deletions core/lib/eth_client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ use std::fmt;

use async_trait::async_trait;
use zksync_types::{
eth_sender::EthTxBlobSidecar,
web3::{
contract::Options,
ethabi,
types::{
Address, Block, BlockId, BlockNumber, Filter, Log, Transaction, TransactionReceipt,
H160, H256, U256, U64,
AccessList, Address, Block, BlockId, BlockNumber, Filter, Log, Transaction,
TransactionCondition, TransactionReceipt, H160, H256, U256, U64,
},
},
L1ChainId,
Expand All @@ -21,6 +21,47 @@ pub use crate::types::{
pub mod clients;
mod types;

/// Contract Call/Query Options
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Options {
/// Fixed gas limit
pub gas: Option<U256>,
/// Fixed gas price
pub gas_price: Option<U256>,
/// Value to transfer
pub value: Option<U256>,
/// Fixed transaction nonce
pub nonce: Option<U256>,
/// A condition to satisfy before including transaction.
pub condition: Option<TransactionCondition>,
/// Transaction type, Some(1) for AccessList transaction, None for Legacy
pub transaction_type: Option<U64>,
/// Access list
pub access_list: Option<AccessList>,
/// Max fee per gas
pub max_fee_per_gas: Option<U256>,
/// miner bribe
pub max_priority_fee_per_gas: Option<U256>,
/// Max fee per blob gas
pub max_fee_per_blob_gas: Option<U256>,
/// Blob versioned hashes
pub blob_versioned_hashes: Option<Vec<H256>>,
/// Blob sidecar
pub blob_tx_sidecar: Option<EthTxBlobSidecar>,
}

impl Options {
/// Create new default `Options` object with some modifications.
pub fn with<F>(func: F) -> Options
where
F: FnOnce(&mut Options),
{
let mut options = Options::default();
func(&mut options);
options
}
}

/// Common Web3 interface, as seen by the core applications.
/// Encapsulates the raw Web3 interaction, providing a high-level interface.
///
Expand Down
1 change: 1 addition & 0 deletions core/lib/eth_client/src/testdata/4844_tx_1.txt

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions core/lib/eth_client/src/testdata/4844_tx_2.txt

Large diffs are not rendered by default.

Loading
Loading