Skip to content

Commit

Permalink
feat(core): Adds support for 4844 transaction signing and rlp encoding (
Browse files Browse the repository at this point in the history
#1254)

## What ❔

Splits the part off of #1056 

## Why ❔

<!-- Why are these changes done? What goal do they contribute to? What
are the principles behind them? -->
<!-- Example: PR templates ensure PR reviewers, observers, and future
iterators are in context about the evolution of repos. -->

## Checklist

<!-- Check your PR fulfills the following items. -->
<!-- For draft PRs check the boxes as you complete them. -->

- [ ] PR title corresponds to the body of PR (we generate changelog
entries from PRs).
- [ ] Tests for the changes have been added / updated.
- [ ] Documentation comments have been added / updated.
- [ ] Code has been formatted via `zk fmt` and `zk lint`.
- [ ] Spellcheck has been run via `zk spellcheck`.
- [ ] Linkcheck has been run via `zk linkcheck`.
  • Loading branch information
montekki committed Feb 26, 2024
1 parent 1d3373b commit 10e3a3e
Show file tree
Hide file tree
Showing 18 changed files with 488 additions and 40 deletions.
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.

0 comments on commit 10e3a3e

Please sign in to comment.