Skip to content

Commit

Permalink
Merge remote-tracking branch 'ml/main' into grw/feat-impl-zks-get-raw…
Browse files Browse the repository at this point in the history
…-block-transactions
  • Loading branch information
grw-ms committed Oct 18, 2023
2 parents f73fb9f + ee35740 commit 03fbdc4
Show file tree
Hide file tree
Showing 11 changed files with 517 additions and 22 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ Please note that `era-test-node` is still in its **alpha** stage. Some features
make run
```

## 📄 System Contracts

The system contract within the node can be specified via the `--dev-system-contracts` option.
It can take one of the following options:
* `built-in`: Use the compiled built-in contracts
* `built-in-no-verify`: Use the compiled built-in contracts, but without signature verification
* `local`: Load contracts from `ZKSYNC_HOME`

## 📃 Logging

The node may be started in either of `debug`, `info`, `warn` or `error` logging levels via the `--log` option:
Expand Down
28 changes: 27 additions & 1 deletion SUPPORTED_APIS.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ The `status` options are:
| [`ZKS`](#zks-namespace) | [`zks_estimateFee`](#zks_estimateFee) | `SUPPORTED` | Gets the Fee estimation data for a given Request |
| `ZKS` | `zks_estimateGasL1ToL2` | `NOT IMPLEMENTED` | Estimate of the gas required for a L1 to L2 transaction |
| `ZKS` | `zks_getAllAccountBalances` | `NOT IMPLEMENTED` | Returns all balances for confirmed tokens given by an account address |
| [`ZKS`](#zks-namespace) | [`zks_getBridgeContracts`](#zks_getbridgecontracts) | `SUPPORTED` | Returns L1/L2 addresses of default bridges |
| [`ZKS`](#zks-namespace) | [`zks_getBlockDetails`](#zks_getblockdetails) | `SUPPORTED` | Returns additional zkSync-specific information about the L2 block |
| `ZKS` | `zks_getBridgeContracts` | `NOT IMPLEMENTED` | Returns L1/L2 addresses of default bridges |
| `ZKS` | `zks_getBytecodeByHash` | `NOT IMPLEMENTED` | Returns bytecode of a transaction given by its hash |
| `ZKS` | `zks_getConfirmedTokens` | `NOT IMPLEMENTED` | Returns [address, symbol, name, and decimal] information of all tokens within a range of ids given by parameters `from` and `limit` |
| `ZKS` | `zks_getL1BatchBlockRange` | `NOT IMPLEMENTED` | Returns the range of blocks contained within a batch given by batch number |
Expand Down Expand Up @@ -1766,6 +1766,32 @@ curl --request POST \
--data '{"jsonrpc": "2.0", "id": 1, "method": "zks_getBlockDetails", "params": [ 140599 ]}'
```

### `zks_getBridgeContracts`

[source](src/zks.rs)

Returns L1/L2 addresses of default bridges.

#### Arguments

+ _NONE_

#### Status

`SUPPORTED`

#### Example

```bash
curl --request POST \
--url http://localhost:8011/ \
--header 'content-type: application/json' \
--data '{
"jsonrpc": "2.0",
"id": "2",
"method": "zks_getBridgeContracts"
}'
```

### `zks_getRawBlockTransactions`

Expand Down
49 changes: 48 additions & 1 deletion e2e-tests/test/zks-apis.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { expect } from "chai";
import { deployContract, getTestProvider } from "../helpers/utils";
import * as hre from "hardhat";
import { Wallet } from "zksync-web3";
import { RichAccounts } from "../helpers/constants";
import { ethers } from "ethers";
import * as hre from "hardhat";
import { TransactionRequest } from "zksync-web3/build/src/types";
import { Deployer } from "@matterlabs/hardhat-zksync-deploy";

Expand Down Expand Up @@ -75,6 +75,19 @@ describe("zks_getTransactionDetails", function () {
});
});

describe("zks_getBridgeContracts", function () {
it("Should return default values", async function () {
const bridgeAddresses = await provider.send("zks_getBridgeContracts", []);

expect(bridgeAddresses).to.deep.equal({
l1Erc20DefaultBridge: "0x0000000000000000000000000000000000000000",
l2Erc20DefaultBridge: "0x0000000000000000000000000000000000000000",
l1WethBridge: null,
l2WethBridge: null,
});
});
});

describe("zks_getBlockDetails", function () {
it("Should return block details for locally-produced blocks", async function () {
const wallet = new Wallet(RichAccounts[0].PrivateKey);
Expand All @@ -90,6 +103,40 @@ describe("zks_getBlockDetails", function () {
});
});

describe("zks_getBytecodeByHash", function () {
it("Should fetch the stored bytecode at address", async function () {
// Arrange
const wallet = new Wallet(RichAccounts[0].PrivateKey);
const deployer = new Deployer(hre, wallet);
const artifact = await deployer.loadArtifact("Greeter");
const greeter = await deployContract(deployer, "Greeter", ["Hi"]);
const deployedContract = await greeter.deployTransaction.wait();
expect(await greeter.greet()).to.eq("Hi");

// get the bytecode hash from the event
const contractDeployedHash = ethers.utils
.keccak256(ethers.utils.toUtf8Bytes("ContractDeployed(address,bytes32,address)"))
.substring(2);
const logs = await provider.send("eth_getLogs", [
{
fromBlock: ethers.utils.hexlify(deployedContract.blockNumber),
toBlock: ethers.utils.hexlify(deployedContract.blockNumber),
address: "0x0000000000000000000000000000000000008006", // L2 Deployer address
topics: [contractDeployedHash],
},
]);
expect(logs).to.not.be.empty;
expect(logs[0].topics).to.have.lengthOf(4);
const bytecodeHash = logs[0].topics[2];

// Act
const bytecode = await provider.send("zks_getBytecodeByHash", [bytecodeHash]);

// Assert
expect(ethers.utils.hexlify(bytecode)).to.equal(artifact.deployedBytecode);
});
});

describe("zks_getRawBlockTransactions", function () {
it("Should return transactions for locally-produced blocks", async function () {
const wallet = new Wallet(RichAccounts[0].PrivateKey);
Expand Down
97 changes: 95 additions & 2 deletions src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,22 @@ use std::path::Path;
use std::result::Result;
use std::str::FromStr;
use zksync_basic_types::H256;
use zksync_types::api::{Block, Transaction, TransactionVariant};
use zksync_types::api::{Block, BridgeAddresses, Transaction, TransactionVariant};
use zksync_types::Transaction as RawTransaction;

/// Caches full blocks by their hashes
const CACHE_TYPE_BLOCKS_FULL: &str = "blocks_full";
/// Caches minimal blocks by their hashes
const CACHE_TYPE_BLOCKS_MIN: &str = "blocks_min";
/// Caches raw transactions by their hashes
const CACHE_TYPE_BLOCK_RAW_TRANSACTIONS: &str = "block_raw_transactions";
/// Caches transactions by their hashes
const CACHE_TYPE_TRANSACTIONS: &str = "transactions";
/// Caches arbitrary values by their keys
const CACHE_TYPE_KEY_VALUE: &str = "key_value";

/// Caching key for bridge addresses
const CACHE_KEY_BRIDGE_ADDRESSES: &str = "bridge_addresses";

/// Cache configuration. Can be one of:
///
Expand All @@ -40,6 +49,7 @@ pub(crate) struct Cache {
blocks_min: FxHashMap<H256, Block<TransactionVariant>>,
block_raw_transactions: FxHashMap<u64, Vec<RawTransaction>>,
transactions: FxHashMap<H256, Transaction>,
bridge_addresses: Option<BridgeAddresses>,
}

impl Cache {
Expand All @@ -57,6 +67,7 @@ impl Cache {
CACHE_TYPE_BLOCKS_MIN,
CACHE_TYPE_BLOCK_RAW_TRANSACTIONS,
CACHE_TYPE_TRANSACTIONS,
CACHE_TYPE_KEY_VALUE,
] {
fs::remove_dir_all(Path::new(dir).join(cache_type)).unwrap_or_else(|err| {
log::warn!(
Expand All @@ -76,6 +87,7 @@ impl Cache {
CACHE_TYPE_BLOCKS_MIN,
CACHE_TYPE_BLOCK_RAW_TRANSACTIONS,
CACHE_TYPE_TRANSACTIONS,
CACHE_TYPE_KEY_VALUE,
] {
fs::create_dir_all(Path::new(dir).join(cache_type)).unwrap_or_else(|err| {
panic!("failed creating directory {}: {:?}", cache_type, err)
Expand Down Expand Up @@ -186,13 +198,37 @@ impl Cache {
self.transactions.insert(hash, transaction);
}

/// Returns the cached bridge addresses for the provided hash.
pub(crate) fn get_bridge_addresses(&self) -> Option<&BridgeAddresses> {
if matches!(self.config, CacheConfig::None) {
return None;
}

self.bridge_addresses.as_ref()
}

/// Cache default bridge addresses.
pub(crate) fn set_bridge_addresses(&mut self, bridge_addresses: BridgeAddresses) {
if matches!(self.config, CacheConfig::None) {
return;
}

self.write_to_disk(
CACHE_TYPE_KEY_VALUE,
String::from(CACHE_KEY_BRIDGE_ADDRESSES),
&bridge_addresses,
);
self.bridge_addresses = Some(bridge_addresses);
}

/// Reads the cache contents from the disk, if available.
fn read_all_from_disk(&mut self, dir: &str) -> Result<(), String> {
for cache_type in [
CACHE_TYPE_BLOCKS_FULL,
CACHE_TYPE_BLOCKS_MIN,
CACHE_TYPE_BLOCK_RAW_TRANSACTIONS,
CACHE_TYPE_TRANSACTIONS,
CACHE_TYPE_KEY_VALUE,
] {
let cache_dir = Path::new(dir).join(cache_type);
let dir_listing = fs::read_dir(cache_dir.clone())
Expand Down Expand Up @@ -252,6 +288,18 @@ impl Cache {
})?;
self.transactions.insert(key, transaction);
}
CACHE_TYPE_KEY_VALUE => match key.as_str() {
CACHE_KEY_BRIDGE_ADDRESSES => {
self.bridge_addresses =
Some(serde_json::from_reader(reader).map_err(|err| {
format!(
"failed parsing json for cache file '{:?}': {:?}",
key, err
)
})?);
}
_ => return Err(format!("invalid cache_type_value key {}", cache_type)),
},
_ => return Err(format!("invalid cache_type {}", cache_type)),
}
}
Expand Down Expand Up @@ -282,9 +330,11 @@ impl Cache {
#[cfg(test)]
mod tests {
use tempdir::TempDir;
use zksync_basic_types::U64;
use zksync_basic_types::{H160, U64};
use zksync_types::{Execute, ExecuteTransactionCommon};

use crate::testing;

use super::*;

#[test]
Expand Down Expand Up @@ -330,6 +380,12 @@ mod tests {
received_timestamp_ms: 0,
raw_bytes: None,
}];
let bridge_addresses = BridgeAddresses {
l1_erc20_default_bridge: H160::repeat_byte(0x1),
l2_erc20_default_bridge: H160::repeat_byte(0x2),
l1_weth_bridge: Some(H160::repeat_byte(0x3)),
l2_weth_bridge: Some(H160::repeat_byte(0x4)),
};

let mut cache = Cache::new(CacheConfig::Memory);

Expand All @@ -355,6 +411,12 @@ mod tests {

cache.insert_transaction(H256::zero(), transaction.clone());
assert_eq!(Some(&transaction), cache.get_transaction(&H256::zero()));

cache.set_bridge_addresses(bridge_addresses.clone());
testing::assert_bridge_addresses_eq(
&bridge_addresses,
cache.get_bridge_addresses().expect("expected addresses"),
);
}

#[test]
Expand All @@ -381,6 +443,12 @@ mod tests {
received_timestamp_ms: 0,
raw_bytes: None,
}];
let bridge_addresses = BridgeAddresses {
l1_erc20_default_bridge: H160::repeat_byte(0x1),
l2_erc20_default_bridge: H160::repeat_byte(0x2),
l1_weth_bridge: Some(H160::repeat_byte(0x3)),
l2_weth_bridge: Some(H160::repeat_byte(0x4)),
};

let cache_dir = TempDir::new("cache-test").expect("failed creating temporary dir");
let cache_dir_path = cache_dir
Expand Down Expand Up @@ -416,6 +484,12 @@ mod tests {
cache.insert_transaction(H256::zero(), transaction.clone());
assert_eq!(Some(&transaction), cache.get_transaction(&H256::zero()));

cache.set_bridge_addresses(bridge_addresses.clone());
testing::assert_bridge_addresses_eq(
&bridge_addresses,
cache.get_bridge_addresses().expect("expected addresses"),
);

let new_cache = Cache::new(CacheConfig::Disk {
dir: cache_dir_path,
reset: false,
Expand All @@ -435,6 +509,12 @@ mod tests {
new_cache.get_block_raw_transactions(&0)
);
assert_eq!(Some(&transaction), new_cache.get_transaction(&H256::zero()));
testing::assert_bridge_addresses_eq(
&bridge_addresses,
new_cache
.get_bridge_addresses()
.expect("expected addresses"),
);
}

#[test]
Expand All @@ -461,6 +541,12 @@ mod tests {
received_timestamp_ms: 0,
raw_bytes: None,
}];
let bridge_addresses = BridgeAddresses {
l1_erc20_default_bridge: H160::repeat_byte(0x1),
l2_erc20_default_bridge: H160::repeat_byte(0x2),
l1_weth_bridge: Some(H160::repeat_byte(0x3)),
l2_weth_bridge: Some(H160::repeat_byte(0x4)),
};

let cache_dir = TempDir::new("cache-test").expect("failed creating temporary dir");
let cache_dir_path = cache_dir
Expand Down Expand Up @@ -496,6 +582,12 @@ mod tests {
cache.insert_transaction(H256::zero(), transaction.clone());
assert_eq!(Some(&transaction), cache.get_transaction(&H256::zero()));

cache.set_bridge_addresses(bridge_addresses.clone());
testing::assert_bridge_addresses_eq(
&bridge_addresses,
cache.get_bridge_addresses().expect("expected addresses"),
);

let new_cache = Cache::new(CacheConfig::Disk {
dir: cache_dir_path,
reset: true,
Expand All @@ -506,6 +598,7 @@ mod tests {
assert_eq!(None, new_cache.get_block_hash(&2));
assert_eq!(None, new_cache.get_block_raw_transactions(&0));
assert_eq!(None, new_cache.get_transaction(&H256::zero()));
assert!(new_cache.get_bridge_addresses().is_none());
}

#[test]
Expand Down
9 changes: 6 additions & 3 deletions src/fork.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use zksync_basic_types::{Address, L1BatchNumber, L2ChainId, MiniblockNumber, H25

use zksync_types::{
api::{
Block, BlockDetails, BlockIdVariant, BlockNumber, Transaction, TransactionDetails,
TransactionVariant,
Block, BlockDetails, BlockIdVariant, BlockNumber, BridgeAddresses, Transaction,
TransactionDetails, TransactionVariant,
},
l2::L2Tx,
ProtocolVersionId, StorageKey,
Expand Down Expand Up @@ -130,7 +130,7 @@ impl<S: ForkSource> ForkStorage<S> {
}
}

pub fn load_factory_dep_internal(&self, hash: H256) -> Option<Vec<u8>> {
fn load_factory_dep_internal(&self, hash: H256) -> Option<Vec<u8>> {
let mut mutator = self.inner.write().unwrap();
let local_storage = mutator.raw_storage.load_factory_dep(hash);
if let Some(fork) = &mutator.fork {
Expand Down Expand Up @@ -257,6 +257,9 @@ pub trait ForkSource {
block_number: BlockNumber,
index: Index,
) -> eyre::Result<Option<Transaction>>;

/// Returns addresses of the default bridge contracts.
fn get_bridge_contracts(&self) -> eyre::Result<BridgeAddresses>;
}

/// Holds the information about the original chain.
Expand Down
Loading

0 comments on commit 03fbdc4

Please sign in to comment.